diff --git a/stable b/stable index b592d6584..e38085345 120000 --- a/stable +++ b/stable @@ -1 +1 @@ -v0.16.11 \ No newline at end of file +v0.16.12 \ No newline at end of file diff --git a/v0.16 b/v0.16 index b592d6584..e38085345 120000 --- a/v0.16 +++ b/v0.16 @@ -1 +1 @@ -v0.16.11 \ No newline at end of file +v0.16.12 \ No newline at end of file diff --git a/v0.16.12/.documenter-siteinfo.json b/v0.16.12/.documenter-siteinfo.json new file mode 100644 index 000000000..f0b13f574 --- /dev/null +++ b/v0.16.12/.documenter-siteinfo.json @@ -0,0 +1 @@ +{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-06-21T23:07:18","documenter_version":"1.4.1"}} \ No newline at end of file diff --git a/v0.16.12/apis/categorical_algebra/index.html b/v0.16.12/apis/categorical_algebra/index.html new file mode 100644 index 000000000..62c843c9a --- /dev/null +++ b/v0.16.12/apis/categorical_algebra/index.html @@ -0,0 +1,83 @@ + +Categorical algebra · Catlab.jl

Categorical algebra

Sets and Relations

The following APIs implement FinSet, the category of Finite Sets (actually the skeleton of FinSet). The objects of this category are natural numbers where n represents a set with n elements. The morphisms are functions between such sets. We use the skeleton of FinSet in order to ensure that all sets are finite and morphisms can be stored using lists of integers. Finite relations are built out of FinSet and can be used to do some relational algebra.

Catlab.CategoricalAlgebra.SetsModule

Category of (possibly infinite) sets and functions.

This module defines generic types for the category of sets (SetOb, SetFunction), as well as a few basic concrete types, such as a wrapper type to view Julia types as sets (TypeSet). Extensive support for finite sets is provided by another module, FinSets.

source
Catlab.CategoricalAlgebra.Sets.SetFunctionType

Abstract type for morphism in the category Set.

Every instance of SetFunction{<:SetOb{T},<:SetOb{T′}} is callable with elements of type T, returning an element of type T′.

Note: This type would be better called simply Function but that name is already taken by the base Julia type.

source
Catlab.CategoricalAlgebra.Sets.SetObType

Abstract type for object in the category Set.

The type parameter T is the element type of the set.

Note: This type is more abstract than the built-in Julia types AbstractSet and Set, which are intended for data structures for finite sets. Those are encompassed by the subtype FinSet.

source
AlgebraicInterfaces.ObMethod

Forgetful functor Ob: Cat → Set.

Sends a category to its set of objects and a functor to its object map.

source
Catlab.CategoricalAlgebra.FinSets.FinFunctionType

Function between finite sets.

The function can be defined implicitly by an arbitrary Julia function, in which case it is evaluated lazily, or explictly by a vector of integers. In the vector representation, the function (1↦1, 2↦3, 3↦2, 4↦3), for example, is represented by the vector [1,3,2,3].

FinFunctions can be constructed with or without an explicitly provided codomain. If a codomain is provided, by default the constructor checks it is valid.

This type is mildly generalized by FinDomFunction.

source
Catlab.CategoricalAlgebra.FinSets.FinSetType

Finite set.

A finite set has abstract type FinSet{S,T}. The second type parameter T is the element type of the set and the first parameter S is the collection type, which can be a subtype of AbstractSet or another Julia collection type. In addition, the skeleton of the category FinSet is the important special case S = Int. The set ${1,…,n}$ is represented by the object FinSet(n) of type FinSet{Int,Int}.

source
Catlab.CategoricalAlgebra.FinSets.TabularLimitType

Limit of finite sets viewed as a table.

Any limit of finite sets can be canonically viewed as a table (TabularSet) whose columns are the legs of the limit cone and whose rows correspond to elements of the limit object. To construct this table from an already computed limit, call TabularLimit(::AbstractLimit; ...). The column names of the table are given by the optional argument names.

In this tabular form, applying the universal property of the limit is trivial since it is just tupling. Thus, this representation can be useful when the original limit algorithm does not support efficient application of the universal property. On the other hand, this representation has the disadvantage of generally making the element type of the limit set more complicated.

source
Catlab.CategoricalAlgebra.FinSets.TabularSetType

Finite set whose elements are rows of a table.

The underlying table should be compliant with Tables.jl. For the sake of uniformity, the rows are provided as named tuples, which assumes that the table is not "extremely wide". This should not be a major limitation in practice but see the Tables.jl documentation for further discussion.

source
Catlab.CategoricalAlgebra.FinSets.VarFunctionType

Data type for a morphism of VarSet{T}s. Note we can equivalently view these as morphisms [n]+T -> [m]+T fixing T or as morphisms [n] -> [m]+T, in the typical Kleisli category yoga.

Currently, domains are treated as VarSets. The codom field is treated as a FinSet{Int}. Note that the codom accessor gives a VarSet while the codom field is just that VarSet's FinSet of AttrVars. This could be generalized to being FinSet{Symbol} to allow for symbolic attributes. (Likewise, AttrVars will have to wrap Any rather than Int)

source
Catlab.CategoricalAlgebra.FinRelations.FinRelationType

Binary relation between finite sets.

A morphism in the category of finite sets and relations. The relation can be represented implicitly by an arbitrary Julia function mapping pairs of elements to booleans or explicitly by a matrix (dense or sparse) taking values in the rig of booleans (BoolRig).

source

Free Diagrams, Limits, and Colimits

The following modules define free diagrams in an arbitrary category and specify limit and colimit cones over said diagrams. Thes constructions enjoy the fullest support for FinSet and are used below to define presheaf categories as C-Sets. The general idea of these functions is that you set up a limit computation by specifying a diagram and asking for a limit or colimit cone, which is returned as a struct containing the apex object and the leg morphisms. This cone structure can be queried using the functions apex and legs. Julia's multiple dispatch feature is heavily used to specialize limit and colimit computations for various diagram shapes like product/coproduct and equalizer/coequalizer. As a consumer of this API, it is highly recommended that you use multiple dispatch to specialize your code on the diagram shape whenever possible.

Catlab.CategoricalAlgebra.FreeDiagramsModule

Free diagrams in a category.

A free diagram in a category is a diagram whose shape is a free category. Examples include the empty diagram, pairs of objects, discrete diagrams, parallel pairs, composable pairs, and spans and cospans. Limits and colimits are most commonly taken over free diagrams.

source
Catlab.CategoricalAlgebra.FreeDiagrams.BipartiteFreeDiagramType

A free diagram with a bipartite structure.

Such diagrams include most of the fixed shapes, such as spans, cospans, and parallel morphisms. They are also the generic shape of diagrams for limits and colimits arising from undirected wiring diagrams. For limits, the boxes correspond to vertices in $V₁$ and the junctions to vertices in $V₂$. Colimits are dual.

source
Catlab.CategoricalAlgebra.FreeDiagrams.BipartiteFreeDiagramMethod

Convert a free diagram to a bipartite free diagram.

Reduce a free diagram to a free bipartite diagram with the same limit (the default, colimit=false) or the same colimit (colimit=true). The reduction is essentially the same in both cases, except for the choice of where to put isolated vertices, where we follow the conventions described at cone_objects and cocone_objects. The resulting object is a bipartite free diagram equipped with maps from the vertices of the bipartite diagram to the vertices of the original diagram.

source
Catlab.CategoricalAlgebra.FreeDiagrams.bundle_legsMethod

Bundle together legs of a multi(co)span.

For example, calling bundle_legs(span, SVector((1,2),(3,4))) on a multispan with four legs gives a span whose left leg bundles legs 1 and 2 and whose right leg bundles legs 3 and 4. Note that in addition to bundling, this function can also permute legs and discard them.

The bundling is performed using the universal property of (co)products, which assumes that these (co)limits exist.

source
Catlab.CategoricalAlgebra.FreeDiagrams.cone_objectsMethod

Objects in diagram that will have explicit legs in limit cone.

In category theory, it is common practice to elide legs of limit cones that can be computed from other legs, especially for diagrams of certain fixed shapes. For example, when it taking a pullback (the limit of a cospan), the limit object is often treated as having two projections, rather than three. This function encodes such conventions by listing the objects in the diagram that will have corresponding legs in the limit object created by Catlab.

See also: cocone_objects.

source
Catlab.CategoricalAlgebra.Limits.SpecializeLimitType

Meta-algorithm that reduces general limits to common special cases.

Reduces limits of free diagrams that happen to be discrete to products. If this fails, fall back to the given algorithm (if any).

TODO: Reduce free diagrams that are (multi)cospans to (wide) pullbacks.

source
Catlab.CategoricalAlgebra.Limits.colimitMethod

Colimit of a diagram.

To define colimits in a category with objects Ob, override the method colimit(::FreeDiagram{Ob}) for general colimits or colimit(::D) with suitable type D <: FixedShapeFreeDiagram{Ob} for colimits of specific shape, such as coproducts or coequalizers.

See also: limit

source
Catlab.CategoricalAlgebra.Limits.epi_monoMethod

The image and coimage are isomorphic. We get this isomorphism using univeral properties.

  CoIm′ ╌╌> I ↠ CoIm
+    ┆ ⌟     |
+    v       v
+    I   ⟶  R ↩ Im
+    |       ┆
+    v    ⌜  v
+    R ╌╌> Im′
source
Catlab.CategoricalAlgebra.Limits.limitMethod

Limit of a diagram.

To define limits in a category with objects Ob, override the method limit(::FreeDiagram{Ob}) for general limits or limit(::D) with suitable type D <: FixedShapeFreeDiagram{Ob} for limits of specific shape, such as products or equalizers.

See also: colimit

source
Catlab.CategoricalAlgebra.Limits.pullbackMethod

Pullback of a pair of morphisms with common codomain.

To implement for a type T, define the method limit(::Cospan{T}) and/or limit(::Multicospan{T}) or, if you have already implemented products and equalizers, rely on the default implementation.

source
Catlab.CategoricalAlgebra.Limits.pushoutMethod

Pushout of a pair of morphisms with common domain.

To implement for a type T, define the method colimit(::Span{T}) and/or colimit(::Multispan{T}) or, if you have already implemented coproducts and coequalizers, rely on the default implementation.

source
Catlab.Theories.coequalizerMethod

Coequalizer of morphisms with common domain and codomain.

To implement for a type T, define the method colimit(::ParallelPair{T}) or colimit(::ParallelMorphisms{T}).

source
Catlab.Theories.copairMethod

Copairing of morphisms: universal property of coproducts/pushouts.

To implement for coproducts of type T, define the method universal(::BinaryCoproduct{T}, ::Cospan{T}) and/or universal(::Coproduct{T}, ::Multicospan{T}) and similarly for pushouts.

source
Catlab.Theories.coproductMethod

Coproduct of objects.

To implement for a type T, define the method colimit(::ObjectPair{T}) and/or colimit(::DiscreteDiagram{T}).

source
Catlab.Theories.createMethod

Unique morphism out of an initial object.

To implement for a type T, define the method universal(::Initial{T}, ::SMulticospan{0,T}).

source
Catlab.Theories.deleteMethod

Unique morphism into a terminal object.

To implement for a type T, define the method universal(::Terminal{T}, ::SMultispan{0,T}).

source
Catlab.Theories.equalizerMethod

Equalizer of morphisms with common domain and codomain.

To implement for a type T, define the method limit(::ParallelPair{T}) and/or limit(::ParallelMorphisms{T}).

source
Catlab.Theories.factorizeMethod

Factor morphism through (co)equalizer, via the universal property.

To implement for equalizers of type T, define the method universal(::Equalizer{T}, ::SMultispan{1,T}). For coequalizers of type T, define the method universal(::Coequalizer{T}, ::SMulticospan{1,T}).

source
Catlab.Theories.pairMethod

Pairing of morphisms: universal property of products/pullbacks.

To implement for products of type T, define the method universal(::BinaryProduct{T}, ::Span{T}) and/or universal(::Product{T}, ::Multispan{T}) and similarly for pullbacks.

source
Catlab.Theories.productMethod

Product of objects.

To implement for a type T, define the method limit(::ObjectPair{T}) and/or limit(::DiscreteDiagram{T}).

source
Catlab.Theories.universalFunction
universal(lim,cone)

Universal property of (co)limits.

Compute the morphism whose existence and uniqueness is guaranteed by the universal property of (co)limits.

See also: limit, colimit.

source

Categories

Catlab.CategoricalAlgebra.CategoriesModule

2-category of categories, functors, and natural transformations.

Categories in mathematics appear in the large, often as categories of sets with extra structure, and in the small, as algebraic structures that generalize groups, monoids, preorders, and graphs. This division manifests in Catlab as well. Large categories (in spirit, if not in the technical sense) occur throughout Catlab as @instances of the theory of categories. For computational reasons, small categories are usually presented by generators and relations.

This module provides a minimal interface to accomodate both situations. Category instances are supported through the wrapper type TypeCat. Finitely presented categories are provided by another module, FinCats.

source
Catlab.CategoricalAlgebra.Categories.CategoryType

Abstract base type for a category.

The objects and morphisms in the category have Julia types Ob and Hom, respectively. Note that these types do not necessarily form an @instance of the theory of categories, as they may not meaningfully form a category outside the context of this object. For example, a finite category regarded as a reflexive graph with a composition operation might have type Cat{Int,Int}, where the objects and morphisms are numerical identifiers for vertices and edges in the graph.

The basic operations available in any category are: dom, codom, id, compose.

source
Catlab.CategoricalAlgebra.Categories.FunctorType

Abstract base type for a functor between categories.

A functor has a domain and a codomain (dom and codom), which are categories, and object and morphism maps, which can be evaluated using ob_map and hom_map. The functor object can also be called directly when the objects and morphisms have distinct Julia types. This is sometimes but not always the case (see Category), so when writing generic code one should prefer the ob_map and hom_map functions.

source
Catlab.CategoricalAlgebra.Categories.TransformationType

Abstract base type for a natural transformation between functors.

A natural transformation $α: F ⇒ G$ has a domain $F$ and codomain $G$ (dom and codom), which are functors $F,G: C → D$ having the same domain $C$ and codomain $D$. The transformation consists of a component $αₓ: Fx → Gx$ in $D$ for each object $x ∈ C$, accessible using component or indexing notation (Base.getindex).

source
AlgebraicInterfaces.obFunction

Coerce or look up object in category.

Converts the input to an object in the category, which should be of type Ob in a category of type Cat{Ob,Hom}. How this works depends on the category, but a common case is to look up objects, which might be integers or GAT expressions, by their human-readable name, usually a symbol.

See also: hom.

source
GATlab.Stdlib.StdModels.opMethod

Oppositization 2-functor.

The oppositization endo-2-functor on Cat, sending a category to its opposite, is covariant on objects and morphisms and contravariant on 2-morphisms, i.e., is a 2-functor $op: Catᶜᵒ → Cat$. For more explanation, see the nLab.

source
Catlab.CategoricalAlgebra.FinCatsModule

2-category of finitely presented categories.

This module is for the 2-category Cat what the module FinSets is for the category Set: a finitary, combinatorial setting where explicit calculations can be carried out. We emphasize that the prefix Fin means "finitely presented," not "finite," as finite categories are too restrictive a notion for many purposes. For example, the free category on a graph is finite if and only if the graph is DAG, which is a fairly special condition. This usage of Fin is also consistent with FinSet because for sets, being finite and being finitely presented are equivalent.

source
Catlab.CategoricalAlgebra.FinCats.FinCatGraphEqType

Category presented by a finite graph together with path equations.

The objects of the category are vertices in the graph and the morphisms are paths, quotiented by the congruence relation generated by the path equations. See (Spivak, 2014, Category theory for the sciences, §4.5).

source
Catlab.CategoricalAlgebra.FinCats.FinCatPresentationType

Category defined by a Presentation object.

The presentation type can, of course, be a category (Theories.Category). It can also be a schema (Theories.Schema). In this case, the schema's objects and attribute types are regarded as the category's objects and the schema's morphisms, attributes, and attribute types as the category's morphisms (where the attribute types are identity morphisms). When the schema is formalized as a profunctor whose codomain category is discrete, this amounts to taking the collage of the profunctor.

source
Catlab.CategoricalAlgebra.FinCats.FinTransformationType

A natural transformation whose domain category is finitely generated.

This type is for natural transformations $α: F ⇒ G: C → D$ such that the domain category $C$ is finitely generated. Such a natural transformation is given by a finite amount of data (one morphism in $D$ for each generating object of $C$) and its naturality is verified by finitely many equations (one equation for each generating morphism of $C$).

source
Catlab.CategoricalAlgebra.FinCats.dom_to_graphMethod

Reinterpret a functor on a finitely presented category as a functor on the equivalent category (ignoring equations) free on a graph. Also normalizes the input to have vector obmap and hommap, with valtype optionally specified. This is useful when the domain is empty or when the maps might be tightly typed but need to allow for types such as that of identity morphisms upon mutation.

source
Catlab.CategoricalAlgebra.FinCats.forceFunction

Force evaluation of lazily defined function or functor. The resulting obmap and hommap are guaranteed to have valtype or eltype, as appropriate, equal to Ob and Hom, respectively.

source
Catlab.CategoricalAlgebra.FinCats.hom_generatorFunction

Coerce or look up morphism generator in a finitely presented category.

Since morphism generators often have a different data type than morphisms (e.g., in a free category on a graph, the morphism generators are edges and the morphisms are paths), the return type of this function is generally different than that of hom.

source
Catlab.CategoricalAlgebra.FinCats.is_functorialMethod

Is the purported functor on a presented category functorial?

This function checks that functor preserves domains and codomains. When check_equations is true (the default is false), it also purports to check that the functor preserves all equations in the domain category. No nontrivial checks are currently implemented, so this only functions for identity functors.

See also: `functoriality_failures' and is_natural.

source
Catlab.CategoricalAlgebra.FinCats.is_initialMethod

Dual to a final functor, an initial functor is one for which pulling back diagrams along it does not change the limits of these diagrams.

This amounts to checking, for a functor C->D, that, for every object d in Ob(D), the comma category (F/d) is connected.

source
Catlab.CategoricalAlgebra.FinCats.is_naturalMethod

Is the transformation between FinDomFunctors a natural transformation?

This function uses the fact that to check whether a transformation is natural, it suffices to check the naturality equations on a generating set of morphisms of the domain category. In some cases, checking the equations may be expensive or impossible. When the keyword argument check_equations is false, only the domains and codomains of the components are checked.

See also: is_functorial.

source
Catlab.CategoricalAlgebra.FinCats.make_mapMethod

Maps f over a UnitRange to produce a Vector, or else over anything to produce a Dict. The type paramter functions to ensure the return type is as desired even when the input is empty.

source
Catlab.CategoricalAlgebra.FinCats.ob_generatorFunction

Coerce or look up object generator in a finitely presented category.

Because object generators usually coincide with objects, the default method for ob in finitely presented categories simply calls this function.

source
Catlab.CategoricalAlgebra.FinCats.ob_generatorsFunction

Object generators of finitely presented category.

The object generators of finite presented category are almost always the same as the objects. In principle, however, it is possible to have equations between objects, so that there are fewer objects than object generators.

source

Acsets

Overview and Theory

For an in depth look into the theory behind acsets, we refer the reader to our paper on the subject, which also gives some sense as to how the implementation works. Here, we give a brief tutorial before the the API documentation.

The most essential part of the acset machinery is the schema. The schema parameterizes the acset: each schema corresponds to a different type of acset. Schemas consist of four parts.

  • Objects $X,Y$ ((X,Y,Z)::Ob)
  • Homomorphisms $f \colon X \to Y$ (f :: Hom(X,Y)), which go from objects to objects
  • Attribute types $\mathtt{T}$ (T :: AttrType)
  • Attributes $a \colon X \to \mathtt{T}$ (a :: Attr(X,T)), which go from objects to data types

For those with a categorical background, a schema is a presentation of a category $|S|$ along with a functor $S$ from $|S|$ to the arrow category $0 \to 1$, such that $S^{-1}(1)$ is discrete.

An acset $F$ on a schema consists of...

  • a set $F(X)$ of "primary keys" for each object
  • a function $F(f) \colon F(X) \to F(Y)$ for each morphism
  • a Julia data type $F(\mathtt{T})$ for each data type $\mathtt{T}$
  • a function $F(a) \colon F(X) \to F(\mathtt{T})$ for each attribute $a$.

For those with a categorical background, an acset on a schema $S$ consists of a functor from $S$ to $\mathsf{Set}$, such that objects in $S^{-1}(0)$ map to finite sets, and objects in $S^{-1}(1)$ map to sets that represent types. For any particular functor $K \colon S^{-1}(1) \to \mathsf{Set}$, we can also take the category of acsets that restrict to this map on $S^{-1}$.

We can also add equations to this presentation, but we currently do nothing with those equations in the implementation; they mostly serve as documentation.

We will now give an example of how this all works in practice.

using GATlab, Catlab.CategoricalAlgebra
+
+# Write down the schema for a weighted graph
+@present SchWeightedGraph(FreeSchema) begin
+  V::Ob
+  E::Ob
+  src::Hom(E,V)
+  tgt::Hom(E,V)
+  T::AttrType
+  weight::Attr(E,T)
+end
+
+# Construct the type used to store acsets on the previous schema
+# We *index* src and tgt, which means that we store not only
+# the forwards map, but also the backwards map.
+@acset_type WeightedGraph(SchWeightedGraph, index=[:src,:tgt])
+
+# Construct a weighted graph, with floats as edge weights
+g = @acset WeightedGraph{Float64} begin
+  V = 4
+  E = 5
+  src = [1,1,1,2,3]
+  tgt = [2,3,4,4,4]
+  weight = [7.2, 9.3, 9.4, 0.1, 42.0]
+end
+Main.__atexample__265.WeightedGraph{Float64} {V:4, E:5, T:0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Esrctgtweight
1127.2
2139.3
3149.4
4240.1
53442.0
+
+

API

The mathematical abstraction of an acset can of course be implemented in many different ways. Currently, there are three implementations of acsets in Catlab, which share a great deal of code.

These implementations can be split into two categories.

The first category is static acset types. In this implementation, different schemas correspond to different Julia types. Methods on these Julia types are then custom-generated for the schema, using CompTime.jl.

Under this category, there are two classes of static acset types. The first class is acset types that are generated using the @acset_type macro. These acset types are custom-derived structs. The advantage of this is that the structs have names like Graph or WiringDiagram that are printed out in error messages. The disadvantage is that if you are taking in schemas at runtime, you have to eval code in order to use them.

Here is an example of using @acset_type

@acset_type WeightedGraph(SchWeightedGraph, index=[:src,:tgt])
+g = WeightedGraph()

The second class is AnonACSets. Like acset types derived from @acset_type, these contain the schema in their type. However, they also contain the type of their fields in their types, so the types printed out in error messages are long and ugly. The advantage of these is that they can be used in situations where the schema is passed in at runtime, and they don't require using eval to create a new acset type.

Here is an example of using AnonACSet

const WeightedGraph = AnonACSetType(SchWeightedGraph, index=[:src,:tgt])
+g = WeightedGraph()

The second category is dynamic acset types. Currently, there is just one type that falls under this category: DynamicACSet. This type has a field for the schema, and no code-generation is done for operations on acsets of this type. This means that if the schema is large compared to the data, this type will often be faster than the static acsets.

However, dynamics acsets are a new addition to Catlab, and much of the machinery of limits, colimits, and other high-level acset constructions assumes that the schema of an acset can be derived from the type. Thus, more work will have to be done before dynamic acsets become a drop-in replacement for static acsets.

Here is an example of using a dynamic acset

g = DynamicACSet("WeightedGraph", SchWeightedGraph; index=[:src,:tgt])
Catlab.CategoricalAlgebra.CSets.ACSetTransformationType

Transformation between attributed C-sets.

Homomorphisms of attributed C-sets generalize homomorphisms of C-sets (CSetTransformation), which you should understand before reading this.

A homomorphism of attributed C-sets with schema S: C ↛ A (a profunctor) is a natural transformation between the corresponding functors col(S) → Set, where col(S) is the collage of S. When the components on attribute types, indexed by objects of A, are all identity functions, the morphism is called tight; in general, it is called loose. With this terminology, acsets on a fixed schema are the objects of an ℳ-category (see Catlab.Theories.MCategory). Calling ACSetTransformation will construct a tight or loose morphism as appropriate, depending on which components are specified.

Since every tight morphism can be considered a loose one, the distinction between tight and loose may seem a minor technicality, but it has important consequences because limits and colimits in a category depend as much on the morphisms as on the objects. In particular, limits and colimits of acsets differ greatly depending on whether they are taken in the category of acsets with tight morphisms or with loose morphisms. Tight morphisms suffice for many purposes, including most applications of colimits. However, when computing limits of acsets, loose morphisms are usually preferable. For more information about limits and colimits in these categories, see TightACSetTransformation and LooseACSetTransformation.

source
Catlab.CategoricalAlgebra.CSets.CSetTransformationType

Transformation between C-sets.

Recall that a C-set homomorphism is a natural transformation: a transformation between functors C → Set satisfying the naturality axiom for every morphism, or equivalently every generating morphism, in C.

This data type records the data of a C-set transformation. Naturality is not strictly enforced but is expected to be satisfied. It can be checked using the function is_natural.

If the schema of the dom and codom has attributes, this has the semantics of being a valid C-set transformation on the combinatorial data alone (including attribute variables, if any).

source
Catlab.CategoricalAlgebra.CSets.LooseACSetTransformationType

Loose transformation between attributed C-sets.

Limits and colimits in the category of attributed C-sets and loose homomorphisms are computed pointwise on both objects and attribute types. This implies that (co)limits of Julia types must be computed. Due to limitations in the expressivity of Julia's type system, only certain simple kinds of (co)limits, such as products, are supported.

Alternatively, colimits involving loose acset transformations can be constructed with respect to explicitly given attribute type components for the legs of the cocone, via the keyword argument type_components to colimit and related functions. This uses the universal property of the colimit. To see how this works, notice that a diagram of acsets and loose acset transformations can be expressed as a diagram D: J → C-Set (for the C-sets) along with another diagram A: J → C-Set (for the attribute sets) and a natural transformation α: D ⇒ A (assigning attributes). Given a natural transformation τ: A ⇒ ΔB to a constant functor ΔB, with components given by type_components, the composite transformation α⋅τ: D ⇒ ΔB is a cocone under D, hence factors through the colimit cocone of D. This factoring yields an assigment of attributes to the colimit in C-Set.

For the distinction between tight and loose, see ACSetTranformation.

source
Catlab.CategoricalAlgebra.CSets.TightACSetTransformationType

Tight transformation between attributed C-sets.

The category of attributed C-sets and tight homomorphisms is isomorphic to a slice category of C-Set, as explained in our paper "Categorical Data Structures for Technical Computing". Colimits in this category thus reduce to colimits of C-sets, by a standard result about slice categories. Limits are more complicated and are currently not supported.

For the distinction between tight and loose, see ACSetTranformation.

source
Catlab.CategoricalAlgebra.CSets.in_boundsMethod

Check whether an ACSetTransformation is still valid, despite possible deletion of elements in the codomain. An ACSetTransformation that isn't in bounds will throw an error, rather than return false, if run through is_natural.

source
Catlab.CategoricalAlgebra.CSets.naturality_failuresMethod

Returns a dictionary whose keys are contained in the names in arrows(S) and whose value at :f, for an arrow (f,c,d), is a lazy iterator over the elements of X(c) on which α's naturality square for f does not commute. Components should be a NamedTuple or Dictionary with keys contained in the names of S's morphisms and values vectors or dicts defining partial functions from X(c) to Y(c).

source
Catlab.CategoricalAlgebra.FinCats.is_naturalMethod

Check naturality condition for a purported ACSetTransformation, α: X→Y. For each hom in the schema, e.g. h: m → n, the following square must commute:

     αₘ
+  Xₘ --> Yₘ
+Xₕ ↓  ✓  ↓ Yₕ
+  Xₙ --> Yₙ
+     αₙ

You're allowed to run this on a named tuple partly specifying an ACSetTransformation, though at this time the domain and codomain must be fully specified ACSets.

source
Catlab.CategoricalAlgebra.FunctorialDataMigrations.internal_homMethod

Objects: Fᴳ(c) = C-Set(C × G, F) where C is the representable c

Given a map f: a->b, we compute that f(Aᵢ) = Bⱼ by constructing the following: Aᵢ A × G → F f*↑ ↑ ↑ ↗ Bⱼ find the hom Bⱼ that makes this commute B × G

where f* is given by yoneda.

source
Catlab.CategoricalAlgebra.FunctorialDataMigrations.representableMethod

Construct a representable C-set.

Recall that a representable C-set is one of form $C(c,-): C → Set$ for some object $c ∈ C$.

This function computes the $c$ representable as the left pushforward data migration of the singleton ${c}$-set along the inclusion functor ${c} ↪ C$, which works because left Kan extensions take representables to representables (Mac Lane 1978, Exercise X.3.2). Besides the intrinsic difficulties with representables (they can be infinite), this function thus inherits any limitations of our implementation of left pushforward data migrations.

source
Catlab.CategoricalAlgebra.FunctorialDataMigrations.subobject_classifierMethod

The subobject classifier Ω in a presheaf topos is the presheaf that sends each object A to the set of sieves on it (equivalently, the set of subobjects of the representable presheaf for A). Counting subobjects gives us the number of A parts; the hom data for f:A->B for subobject Aᵢ is determined via:

Aᵢ ↪ A ↑ ↑ f* PB⌝↪ B (PB picks out a subobject of B, up to isomorphism.)

(where A and B are the representables for objects A and B and f* is the unique map from B into the A which sends the point of B to f applied to the point of A)

Returns the classifier as well as a dictionary of subobjects corresponding to the parts of the classifier.

source
Catlab.CategoricalAlgebra.FunctorialDataMigrations.yonedaMethod

Compute the Yoneda embedding of a category C in the category of C-sets.

Because Catlab privileges copresheaves (C-sets) over presheaves, this is the contravariant Yoneda embedding, i.e., the embedding functor C^op → C-Set.

The first argument cons is a constructor for the ACSet, such as a struct acset type. If representables have already been computed (which can be expensive), they can be supplied via the cache keyword argument.

Returns a FinDomFunctor with domain op(C).

source
Catlab.CategoricalAlgebra.ChaseModule

The chase is an algorithm which subjects a C-Set instance to constraints expressed in the language of regular logic, called embedded dependencies (EDs, or 'triggers').

A morphism S->T, encodes an embedded dependency. If the pattern S is matched (via a homomorphism S->I), we demand there exist a morphism T->I (for some database instance I) that makes the triangle commute in order to satisfy the dependency (if this is not the case, then the trigger is 'active').

Homomorphisms can merge elements and introduce new ones. The former kind are called "equality generating dependencies" (EGDs) and the latter "tuple generating dependencies" (TGDs). Any homomorphism can be factored into EGD and TGD components by, respectively, restricting the codomain to the image or restricting the domain to the coimage.

source
Catlab.CategoricalAlgebra.Chase.chaseMethod
chase(I::ACSet, Σ::AbstractDict, n::Int)

Chase a C-Set or C-Rel instance given a list of embedded dependencies. This may not terminate, so a bound n on the number of iterations is required.

[,]

ΣS ⟶ Iₙ ⊕↓ ⋮ (resulting morphism) ΣT ... Iₙ₊₁

There is a copy of S and T for each active trigger. A trigger is a map from S into the current instance. What makes it 'active' is that there is no morphism from T to I that makes the triangle commute.

Each iteration constructs the above pushout square. The result is a morphism, so that one can keep track of the provenance of elements in the original CSet instance within the chased result.

Whether or not the result is due to success or timeout is returned as a boolean flag.

TODO: this algorithm could be made more efficient by homomorphism caching.

source
Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanType

Structured cospan.

The first type parameter L encodes a functor L: A → X from the base category A, often FinSet, to a category X with "extra structure." An L-structured cospan is then a cospan in X whose feet are images under L of objects in A. The category X is assumed to have pushouts.

Structured cospans form a double category with no further assumptions on the functor L. To obtain a symmetric monoidal double category, L must preserve finite coproducts. In practice, L usually has a right adjoint R: X → A, which implies that L preserves all finite colimits. It also allows structured cospans to be constructed more conveniently from an object x in X plus a cospan in A with apex R(x).

See also: StructuredMulticospan.

source
Catlab.CategoricalAlgebra.StructuredCospans.OpenACSetTypesMethod

Create types for open attributed C-sets from an attributed C-set type.

The type parameters of the given acset type should not be instantiated with specific Julia types. This function returns a pair of types, one for objects, a subtype of StructuredCospanOb, and one for morphisms, a subtype of StructuredMulticospan. Both types will have the same type parameters for attribute types as the given acset type.

Mathematically speaking, this function sets up structured (multi)cospans with a functor $L: A → X$ between categories of acsets that creates "discrete acsets." Such a "discrete acset functor" is a functor that is left adjoint to a certain kind of forgetful functor between categories of acsets, namely one that is a pullback along an inclusion of schemas such that the image of inclusion has no outgoing arrows. For example, the schema inclusion ${V} ↪ {E ⇉ V}$ has this property but ${E} ↪ {E ⇉ V}$ does not.

See also: OpenCSetTypes.

source
diff --git a/v0.16.12/apis/graphics/index.html b/v0.16.12/apis/graphics/index.html new file mode 100644 index 000000000..80c4e4df6 --- /dev/null +++ b/v0.16.12/apis/graphics/index.html @@ -0,0 +1,2 @@ + +Graphics · Catlab.jl

Graphics

Catlab.Graphics.GraphvizGraphs.parse_graphvizMethod

Parse Graphviz output in JSON format.

Returns a property graph with graph layout and other metadata. Each node has a position and size.

All units are in points. Note that Graphviz has 72 points per inch.

source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Convert a property graph to a Graphviz graph.

This method is usually more convenient than direct AST manipulation for creating simple Graphviz graphs. For more advanced features, like nested subgraphs, you must use the Graphviz AST.

source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Visualize a bipartite graph using Graphviz.

Works for both directed and undirected bipartite graphs. Both types of vertices in the bipartite graph become nodes in the Graphviz graph.

Arguments

  • prog="dot": Graphviz program to use
  • graph_attrs: Graph-level Graphviz attributes
  • node_attrs: Node-level Graphviz attributes
  • edge_attrs: Edge-level Graphviz attributes
  • node_labels=false: whether to label nodes and if so, which pair of data attributes to use
  • edge_labels=false: whether to label edges and if so, which data attribute (undirected case) or pair of attributes (directed case) to use
  • invis_edge=true: whether to add invisible edges between vertices of same type, which ensures that the order of the nodes is preserved.
source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Convert a graph to a Graphviz graph.

A simple default style is applied. For more control over the visual appearance, first convert the graph to a property graph, define the Graphviz attributes as needed, and finally convert the property graph to a Graphviz graph.

source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Visualize a graph homomorphism using Graphviz.

Visualize a homomorphism (ACSetTransformation) between two graphs (instances of AbstractGraph). By default, the domain and codomain are drawn as subgraphs and the vertex mapping is drawn using dotted edges, whereas the edge map is suppressed. The vertex and edge mapping can also be shown using colors, via the node_colors and edge_colors keyword arguments.

Arguments

  • draw_codom=true: whether to draw the codomain graph
  • draw_mapping=true: whether to draw the vertex mapping using edges
  • prog="dot": Graphviz program to use
  • graph_attrs: Graph-level Graphviz attributes
  • node_attrs: Node-level Graphviz attributes
  • edge_attrs: Edge-level Graphviz attributes
  • node_labels=false: whether to draw node labels and which vertex attribute to use
  • edge_labels=false: whether to draw edge labels and which edge attribute to use
  • node_colors=!draw_codom: whether and how to color nodes based on vertex map
  • edge_colors=!draw_codom: whether and how to color edges based on edge map
source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Draw an undirected wiring diagram using Graphviz.

Creates an undirected, bipartite Graphviz graph, with the boxes and outer ports of the diagram becoming nodes of one kind and the junctions of the diagram becoming nodes of the second kind.

Arguments

  • graph_name="G": name of Graphviz graph
  • prog="neato": Graphviz program, usually "neato" or "fdp"
  • box_labels=false: if boolean, whether to label boxes with their number; if a symbol, name of data attribute for box label
  • port_labels=false: whether to label ports with their number
  • junction_labels=false: if boolean, whether to label junctions with their number; if a symbol, name of data attribute for junction label
  • junction_size="0.075": size of junction nodes, in inches
  • implicit_junctions=false: whether to represent a junction implicity as a wire when it has exactly two incident ports
  • graph_attrs=Dict(): top-level graph attributes
  • node_attrs=Dict(): top-level node attributes
  • edge_attrs=Dict(): top-level edge attributes
source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Draw a circular port graph using Graphviz.

Creates a Graphviz graph. Ports are currently not respected in the image, but the port index for each box can be displayed to provide clarification.

Arguments

  • graph_name="G": name of Graphviz graph
  • prog="neato": Graphviz program, usually "neato" or "fdp"
  • box_labels=false: whether to label boxes with their number
  • port_labels=false: whether to label ports with their number
  • graph_attrs=Dict(): top-level graph attributes
  • node_attrs=Dict(): top-level node attributes
  • edge_attrs=Dict(): top-level edge attributes

TODO: The lack of ports might be able to be resolved by introducing an extra node per port which is connected to its box with an edge of length 0.

source
Catlab.Graphics.GraphvizGraphs.to_graphvizMethod

Draw a wiring diagram using Graphviz.

The input can also be a morphism expression, in which case it is first converted into a wiring diagram. This function requires Graphviz v2.42 or higher.

Arguments

  • graph_name="G": name of Graphviz digraph
  • orientation=TopToBottom: orientation of layout. One of LeftToRight, RightToLeft, TopToBottom, or BottomToTop.
  • node_labels=true: whether to label the nodes
  • labels=false: whether to label the edges
  • label_attr=:label: what kind of edge label to use (if labels is true). One of :label, :xlabel, :headlabel, or :taillabel.
  • port_size="24": minimum size of ports on box, in points
  • junction_size="0.05": size of junction nodes, in inches
  • outer_ports=true: whether to display the outer box's input and output ports. If disabled, no incoming or outgoing wires will be shown either!
  • anchor_outer_ports=true: whether to enforce ordering of the outer box's input and output, i.e., ordering of the incoming and outgoing wires
  • graph_attrs=Dict(): top-level graph attributes
  • node_attrs=Dict(): top-level node attributes
  • edge_attrs=Dict(): top-level edge attributes
  • cell_attrs=Dict(): main cell attributes in node HTML-like label
source
Catlab.Graphics.GraphvizWiringDiagrams.graphviz_layoutMethod

Lay out directed wiring diagram using Graphviz.

Note: At this time, only the positions and sizes of the boxes, and the positions of the outer ports, are used. The positions of the box ports and the splines for the wires are ignored.

source
Catlab.Graphics.WiringDiagramLayoutsModule

Backend-agnostic layout of wiring diagrams via morphism expressions.

This module lays out wiring diagrams for visualization, independent of any specific graphics system. It uses the structure of a morphism expression to determine the layout. Thus, the first step of the algorithm is to convert the wiring diagram to a symbolic expression, using the submodule WiringDiagrams.Expressions. Morphism expressions may also be given directly.

source
Catlab.Graphics.WiringDiagramLayouts.layout_diagramMethod

Lay out a wiring diagram or morphism expression for visualization.

If a wiring diagram is given, it is first to converted to a morphism expression.

The layout is calculated with respect to a cartesian coordinate system with origin at the center of the diagram and the positive y-axis pointing downwards. Box positions are relative to their centers. All positions and sizes are dimensionless (unitless).

source
diff --git a/v0.16.12/apis/graphs/index.html b/v0.16.12/apis/graphs/index.html new file mode 100644 index 000000000..a08636b91 --- /dev/null +++ b/v0.16.12/apis/graphs/index.html @@ -0,0 +1,2 @@ + +Graphs · Catlab.jl

Graphs

Catlab.Graphs.BasicGraphsModule

Data structures for graphs, based on C-sets.

This module provides the category theorist's four basic kinds of graphs: graphs (aka directed multigraphs), symmetric graphs, reflexive graphs, and symmetric reflexive graphs. It also defines half-edge graphs, which are isomorphic to symmetric graphs, and a few standard kinds of attributed graphs, such as weighted graphs.

The graphs API generally follows that of Graphs.jl, with some departures due to differences between the data structures.

source
Catlab.Graphs.BasicGraphs.HasGraphType

Abstract type for C-sets that contain a graph.

This type encompasses C-sets where the schema for graphs is a subcategory of C. This includes, for example, graphs, symmetric graphs, and reflexive graphs, but not half-edge graphs.

source
Catlab.Graphs.BasicGraphs.HasVerticesType

Abstract type for C-sets that contain vertices.

This type encompasses C-sets where the schema C contains an object V interpreted as vertices. This includes, for example, graphs and half-edge graphs, but not bipartite graphs or wiring diagrams.

source
Catlab.Graphs.BasicGraphs.LabeledGraphType

A labeled graph.

By convention, a "labeled graph" without qualification is a vertex-labeled graph. We do not require that the label be unique, and in this data type, the label attribute is not indexed.

source
Base.invMethod

Involution on half-edge(s) in a half-edge graph.

source
Catlab.Graphs.BasicGraphs.add_dangling_edge!Method

Add a dangling edge to a half-edge graph.

A "dangling edge" is a half-edge that is paired with itself under the half-edge involution. They are usually interpreted differently than "self-loops", i.e., a pair of distinct half-edges incident to the same vertex.

source
Catlab.Graphs.BasicGraphs.neMethod

Number of edges in a graph, or between two vertices in a graph.

In a symmetric graph, this function counts both edges in each edge pair, so that the number of edges in a symmetric graph is twice the number of edges in the corresponding undirected graph (at least when the edge involution has no fixed points).

source
Catlab.Graphs.BasicGraphs.neighborsMethod

Neighbors of vertex in a graph.

In a graph, this function is an alias for outneighbors; in a symmetric graph, a vertex has the same out-neighbors and as in-neighbors, so the distinction is moot.

In the presence of multiple edges, neighboring vertices are given with multiplicity. To get the unique neighbors, call unique(neighbors(g)).

source
Catlab.Graphs.BasicGraphs.rem_vertex!Method

Remove a vertex from a graph.

When keep_edges is false (the default), all edges incident to the vertex are also deleted. When keep_edges is true, incident edges are preserved but their source/target vertices become undefined.

source
Catlab.Graphs.BipartiteGraphsModule

Bipartite graphs, directed and undirected, as C-sets.

A graph theorist might call these "bipartitioned graphs," as in a graph equipped with a bipartition, as opposed to "bipartite graphs," as in a graph that can be bipartitioned. Here we use the former notion, which is more natural from the structuralist perspective, but the latter terminology, which is shorter and more familiar.

source
Catlab.Graphs.BipartiteGraphs.UndirectedBipartiteGraphType

An undirected bipartite graph.

It is a matter of perspective whether to consider such graphs "undirected," in the sense that the edges have no orientation, or "unidirected," in the sense that all edges go from vertices of type 1 to vertices of type 2.

source
Catlab.Graphs.NamedGraphsModule

Extends the basic graph types with vertex and/or edge names.

Naming vertices and edges and looking them up by name is a common requirement. This module provides a simple interface and default graph types for named graphs. Names are understood to be unique within the graph but are not assumed to be strings or symbols.

source
Catlab.Graphs.PropertyGraphs.PropertyGraphType

Graph with properties.

"Property graphs" are graphs with arbitrary named properties on the graph, vertices, and edges. They are intended for applications with a large number of ad-hoc properties. If you have a small number of known properties, it is better and more efficient to create a specialized C-set type using @acset_type.

See also: SymmetricPropertyGraph.

source
Catlab.Graphs.GraphAlgorithms.transitive_reduction!Method

Transitive reduction of a DAG.

The algorithm computes the longest paths in the DAGs and keeps only the edges corresponding to longest paths of length 1. Requires a topological sort, which is computed if it is not supplied.

source
Catlab.Graphs.GraphGenerators.erdos_renyiMethod
erdos_renyi(GraphType, n, p)

Create an Erdős–Rényi random graph with n vertices. Edges are added between pairs of vertices with probability p.

Optional Arguments

  • seed=-1: set the RNG seed.
  • rng: set the RNG directly

References

  • https://github.com/JuliaGraphs/LightGraphs.jl/blob/2a644c2b15b444e7f32f73021ec276aa9fc8ba30/src/SimpleGraphs/generators/randgraphs.jl
source
Catlab.Graphs.GraphGenerators.expected_degree_graphMethod
expected_degree_graph(GraphType, ω)

Given a vector of expected degrees ω indexed by vertex, create a random undirected graph in which vertices i and j are connected with probability ω[i]*ω[j]/sum(ω).

Optional Arguments

  • seed=-1: set the RNG seed.
  • rng: set the RNG directly

Implementation Notes

The algorithm should work well for maximum(ω) << sum(ω). As maximum(ω) approaches sum(ω), some deviations from the expected values are likely.

References

source
Catlab.Graphs.GraphGenerators.watts_strogatzMethod
watts_strogatz(n, k, β)

Return a Watts-Strogatz small world random graph with n vertices, each with expected degree k (or `k

  • 1ifkis odd). Edges are randomized per the model based on probabilityβ`.

The algorithm proceeds as follows. First, a perfect 1-lattice is constructed, where each vertex has exacly div(k, 2) neighbors on each side (i.e., k or k - 1 in total). Then the following steps are repeated for a hop length i of 1 through div(k, 2).

  1. Consider each vertex s in turn, along with the edge to its ith nearest neighbor t, in a clockwise sense.

  2. Generate a uniformly random number r. If r ≥ β, then the edge (s, t) is left unaltered. Otherwise, the edge is deleted and rewired so that s is connected to some vertex d, chosen uniformly at random from the entire graph, excluding s and its neighbors. (Note that t is a valid candidate.)

For β = 0, the graph will remain a 1-lattice, and for β = 1, all edges will be rewired randomly.

Optional Arguments

  • is_directed=false: if true, return a directed graph.
  • seed=-1: set the RNG seed.

References

source
diff --git a/v0.16.12/apis/programs/index.html b/v0.16.12/apis/programs/index.html new file mode 100644 index 000000000..1ef5bcd46 --- /dev/null +++ b/v0.16.12/apis/programs/index.html @@ -0,0 +1,6 @@ + +Programs · Catlab.jl

Programs

The module Catlab.Programs provides domain-specific languages (DSLs) for constructing diagrams of various kinds. The DSLs, implemented as Julia macros, are based on the syntax of the Julia language but often interpret that syntax very differently from standard Julia programs. Conversely, this module offers preliminary support for generating Julia code from wiring diagrams.

There are two major macros for constructing wiring diagrams:

  • @program, for directed wiring diagrams (DWDs)
  • @relation, for undirected wiring diagrams (UWDs)

There is a family of related macros for constructing category-theoretic diagrams included in DataMigrations.jl.

API

Catlab.Programs.GenerateJuliaPrograms.evaluateMethod

Evaluate a morphism as a function.

If the morphism will be evaluated only once (possibly with vectorized inputs), then direct evaluation will be much faster than compiling (via compile) and evaluating a standard Julia function.

Compare with functor.

source
Catlab.Programs.ParseJuliaPrograms.@programMacro

Parse a wiring diagram from a Julia program.

For the most part, this is standard Julia code but a few liberties are taken with the syntax. Products are represented as tuples. So if x and y are variables of type $X$ and $Y$, then (x,y) has type $X ⊗ Y$. Also, both () and nothing are interpreted as the monoidal unit $I$.

Unlike standard Julia, the function call expressions f(x,y) and f((x,y)) are equivalent. Consequently, given morphisms $f: W → X ⊗ Y$ and $g: X ⊗ Y → Z$, the code

x, y = f(w)
+g(x,y)

is equivalent to g(f(w)). In standard Julia, at most one of these calls to g would be valid, unless g had multiple signatures.

The diagonals (copying and deleting) of a cartesian category are implicit in the Julia syntax: copying is variable reuse and deleting is variable non-use. For the codiagonals (merging and creating), a special syntax is provided, reinterpreting Julia's vector literals. The merging of x1 and x2 is represented by the vector [x1,x2] and creation by the empty vector []. For example, f([x1,x2]) translates to compose(mmerge(X),f).

This macro is a wrapper around parse_wiring_diagram.

source
Catlab.Programs.RelationalPrograms.@relationMacro

Construct an undirected wiring diagram using relation notation.

Unlike the @program macro for directed wiring diagrams, this macro departs significantly from the usual semantics of the Julia programming language. Function calls with $n$ arguments are now interpreted as assertions that an $n$-ary relation holds at a particular point. For example, the composite of binary relations $R ⊆ X × Y$ and $S ⊆ Y × Z$ can be represented as an undirected wiring diagram by the macro call

@relation (x,z) where (x::X, y::Y, z::Z) begin
+  R(x,y)
+  S(y,z)
+end

In general, the context in the where clause defines the set of junctions in the diagram and variable sharing defines the wiring of ports to junctions. If the where clause is omitted, the set of junctions is inferred from the variables used in the macro call.

The ports and junctions of the diagram may be typed or untyped, and the ports may be named or unnamed. Thus, four possible types of undirected wiring diagrams may be returned, with the type determined by the form of relation header:

  1. Untyped, unnamed: @relation (x,z) where (x,y,z) ...
  2. Typed, unnamed: @relation (x,z) where (x::X, y::Y, z::Z) ...
  3. Untyped, named: @relation (out1=x, out2=z) where (x,y,z) ...
  4. Typed, named: @relation (out=1, out2=z) where (x::X, y::Y, z::Z) ...

All four types of diagram are subtypes of RelationDiagram.

source
diff --git a/v0.16.12/apis/theories/index.html b/v0.16.12/apis/theories/index.html new file mode 100644 index 000000000..646285352 --- /dev/null +++ b/v0.16.12/apis/theories/index.html @@ -0,0 +1,2 @@ + +Standard library of theories · Catlab.jl

Standard library of theories

Through the module Catlab.Theories, Catlab provides a standard library of generalized algebraic theories for categories, monoidal categories, and other categorical structures. The theories correspond, in most cases, to standard definitions in category theory and they are used throughout Catlab and the AlgebraicJulia ecosystem to structure programs and provide a common interface for applied category theory. The module also provides default syntax systems for many of the theories.

Categorical structures for which theories are provided include:

  • categories
  • monoidal and symmetric monoidal categories
  • cartesian and cocartesian categories
  • semiadditive categories/biproduct categories
  • hypergraph categories
  • bicategories of relations
  • categories with two monoidal products, such as distributive monoidal categories

The contents of this module can be supplemented by the user, and it is even possible to use many parts of Catlab without using this module. The user is free to create new syntax systems for the theories defined here and also to define entirely new theories.

Catlab.TheoriesModule

Catlab's standard library of generalized algebraic theories.

The focus is on categories and monoidal categories, but other related structures are also included.

source
Catlab.Theories.CategoryExprType

Base type for GAT expressions in categories or other categorical structures.

All symbolic expression types exported by Catlab.Theories are subtypes of this abstract type.

source
Base.collectMethod

Collect generators of object in monoidal category as a vector.

source
Base.ndimsMethod

Number of "dimensions" of object in monoidal category.

source
diff --git a/v0.16.12/apis/wiring_diagrams/index.html b/v0.16.12/apis/wiring_diagrams/index.html new file mode 100644 index 000000000..f8e7d49d2 --- /dev/null +++ b/v0.16.12/apis/wiring_diagrams/index.html @@ -0,0 +1,2 @@ + +Wiring diagrams · Catlab.jl

Wiring diagrams

Catlab.WiringDiagrams.DirectedWiringDiagramsModule

Data structure for (directed) wiring diagrams, aka string diagrams.

A (directed) wiring diagram consists of a collection of boxes with input and output ports connected by wires. A box can be atomic (possessing no internal structure) or can itself be a wiring diagram. Thus, wiring diagrams can be nested recursively. Wiring diagrams are closely related to what the CS literature calls "directed graphs with ports" or more simply "port graphs". The main difference is that a wiring diagram has an "outer box": a wiring diagram has its own ports that can be connected to the ports of its boxes.

This module provides a generic data structure for wiring diagrams. Arbitrary data can be attached to the boxes, ports, and wires of a wiring diagram. The diagrams are "abstract" in the sense that they cannot be directly rendered as raster or vector graphics. However, they form a useful intermediate representation that can be serialized to and from GraphML or translated into Graphviz or other declarative diagram languages.

source
Catlab.CategoricalAlgebra.FinCats.graphMethod

Grapn underlying wiring diagram, including parts for noin-internal wires.

The graph has two special vertices representing the input and output boundaries of the outer box.

source
Catlab.WiringDiagrams.DirectedWiringDiagrams.encapsulated_subdiagramMethod

Create an encapsulating box for a set of boxes in a wiring diagram.

To a first approximation, the union of input ports of the given boxes will become the inputs ports of the encapsulating box and likewise for the output ports. However, when copies or merges occur, as in a cartesian or cocartesian category, a simplification procedure may reduce the number of ports on the encapsulating box.

Specifically:

  1. Each input port of an encapsulated box will have at most one incoming wire

from the encapsulating outer box, and each output port of an encapsulated box will have at most one outgoing wire to the encapsulating outer box.

  1. A set of ports connected to the same outside (non-encapsulated) ports will be

simplified into a single port of the encapsulating box.

See also induced_subdiagram.

source
Catlab.WiringDiagrams.DirectedWiringDiagrams.ocomposeMethod

Operadic composition of wiring diagrams.

This generic function has two different signatures, corresponding to the "full" and "partial" notions of operadic composition (Yau, 2018, Operads of Wiring Diagrams, Definitions 2.3 and 2.10).

This operation is a simple wrapper around substitute.

source
Catlab.WiringDiagrams.DirectedWiringDiagrams.add_wire!Method

Wire together two ports in an undirected wiring diagram.

A convenience method that creates and sets junctions as needed. Ports are only allowed to have one junction, so if both ports already have junctions, then the second port is assigned the junction of the first. The handling of the two arguments is otherwise symmetric.

FIXME: When both ports already have junctions, the two junctions should be merged. To do this, we must implement merge_junctions! and thus also rem_part!.

source
Catlab.WiringDiagrams.MonoidalDirectedWiringDiagramsModule

Wiring diagrams as a symmetric monoidal category.

This module provides a high-level categorical interface to wiring diagrams, building on the low-level imperative interface and the operadic interface. It also defines data types and functions to represent diagonals, codiagonals, duals, caps, cups, daggers, and other gadgets in wiring diagrams.

source
Catlab.WiringDiagrams.WiringDiagramAlgorithms.crossing_minimization_by_sortMethod

Crossing minimization by sorting a univariate statistic.

The boxes in sources and/or targets are fixed and the boxes in vs are permuted. A permutation σ of the latter is returned, such that vs[σ] are the sorted box IDs. Both one-sided and two-sided crossing minimization are supported, depending on whether just one, or both, of sources and targets are given.

In this simple but popular heuristic algorithm, the boxes are permuted by sorting a univariate statistic of the positions of incoming and/or outgoing wires. Typical choices are:

  • mean: the sample mean, yielding the "barycenter method"
  • median: the sample median

In both cases, this algorithm has the property that if there is a permutation with no crossings, it will find it.

source
Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_copy!Method

Normalize copies in a wiring diagram.

This function maximizes sharing of intermediate computations in a wiring diagram where copies are natural.

This algorithm is basically the same as the congruence closure algorithm on term graphs, in the special case of the empty relation R = ∅ (Baader & Nipkow, 1998, Term Rewriting and All That, Sec. 4.4). The main difference is the possibility of zero or many function outputs.

source
Catlab.WiringDiagrams.WiringDiagramSerializationModule

Conventions for serialization of wiring diagrams.

Defines a consistent set of names for boxes, ports, and wires to be used when serializing wiring diagrams, as well as conventions for serializing box, port, and wire attributes.

source
Catlab.WiringDiagrams.GraphMLWiringDiagramsModule

Serialize abstract wiring diagrams as GraphML.

Serialization of box, port, and wire values can be overloaded by data type (see convert_to_graphml_data and convert_from_graphml_data).

GraphML is the closest thing to a de jure and de facto standard in the space of graph data formats, supported by a variety of graph applications and libraries. We depart mildly from the GraphML spec by allowing JSON data attributes for GraphML nodes, ports, and edges.

References:

  • GraphML Primer: http://graphml.graphdrawing.org/primer/graphml-primer.html
  • GraphML DTD: http://graphml.graphdrawing.org/specification/dtd.html
source
Catlab.WiringDiagrams.JSONWiringDiagramsModule

Serialize abstract wiring diagrams as JSON.

JSON data formats are convenient when programming for the web. Unfortunately, no standard for JSON graph formats has gained any kind of widespread adoption. We adopt a format compatible with that used by the KEILER project and its successor ELK (Eclipse Layout Kernel). This format is roughly feature compatible with GraphML, supporting nested graphs and ports. It also supports layout information like node position and size.

References:

  • KEILER's JSON graph format: https://rtsys.informatik.uni-kiel.de/confluence/display/KIELER/JSON+Graph+Format
  • ELK's JSON graph format: https://www.eclipse.org/elk/documentation/tooldevelopers/graphdatastructure/jsonformat.html
source
diff --git a/v0.16.12/assets/analytics.js b/v0.16.12/assets/analytics.js new file mode 100644 index 000000000..6b63df1ae --- /dev/null +++ b/v0.16.12/assets/analytics.js @@ -0,0 +1,11 @@ +var _paq = window._paq = window._paq || []; +/* tracker methods like "setCustomDimension" should be called before "trackPageView" */ +_paq.push(['trackPageView']); +_paq.push(['enableLinkTracking']); +(function() { + var u="https://matomo.mehalter.com/"; + _paq.push(['setTrackerUrl', u+'matomo.php']); + _paq.push(['setSiteId', '8']); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); +})(); diff --git a/v0.16.12/assets/documenter.js b/v0.16.12/assets/documenter.js new file mode 100644 index 000000000..c6562b558 --- /dev/null +++ b/v0.16.12/assets/documenter.js @@ -0,0 +1,1050 @@ +// Generated by Documenter.jl +requirejs.config({ + paths: { + 'highlight-julia': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/julia.min', + 'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.12.0/headroom.min', + 'jqueryui': 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min', + 'katex-auto-render': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min', + 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min', + 'headroom-jquery': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.12.0/jQuery.headroom.min', + 'katex': 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min', + 'highlight': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min', + 'highlight-julia-repl': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/julia-repl.min', + }, + shim: { + "highlight-julia": { + "deps": [ + "highlight" + ] + }, + "katex-auto-render": { + "deps": [ + "katex" + ] + }, + "headroom-jquery": { + "deps": [ + "jquery", + "headroom" + ] + }, + "highlight-julia-repl": { + "deps": [ + "highlight" + ] + } +} +}); +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'katex', 'katex-auto-render'], function($, katex, renderMathInElement) { +$(document).ready(function() { + renderMathInElement( + document.body, + { + "delimiters": [ + { + "left": "$", + "right": "$", + "display": false + }, + { + "left": "$$", + "right": "$$", + "display": true + }, + { + "left": "\\[", + "right": "\\]", + "display": true + } + ] +} + + ); +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'highlight', 'highlight-julia', 'highlight-julia-repl'], function($) { +$(document).ready(function() { + hljs.highlightAll(); +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +let timer = 0; +var isExpanded = true; + +$(document).on("click", ".docstring header", function () { + let articleToggleTitle = "Expand docstring"; + + debounce(() => { + if ($(this).siblings("section").is(":visible")) { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + } else { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); + + articleToggleTitle = "Collapse docstring"; + } + + $(this) + .find(".docstring-article-toggle-button") + .prop("title", articleToggleTitle); + $(this).siblings("section").slideToggle(); + }); +}); + +$(document).on("click", ".docs-article-toggle-button", function (event) { + let articleToggleTitle = "Expand docstring"; + let navArticleToggleTitle = "Expand all docstrings"; + let animationSpeed = event.noToggleAnimation ? 0 : 400; + + debounce(() => { + if (isExpanded) { + $(this).removeClass("fa-chevron-up").addClass("fa-chevron-down"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + + isExpanded = false; + + $(".docstring section").slideUp(animationSpeed); + } else { + $(this).removeClass("fa-chevron-down").addClass("fa-chevron-up"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); + + isExpanded = true; + articleToggleTitle = "Collapse docstring"; + navArticleToggleTitle = "Collapse all docstrings"; + + $(".docstring section").slideDown(animationSpeed); + } + + $(this).prop("title", navArticleToggleTitle); + $(".docstring-article-toggle-button").prop("title", articleToggleTitle); + }); +}); + +function debounce(callback, timeout = 300) { + if (Date.now() - timer > timeout) { + callback(); + } + + clearTimeout(timer); + + timer = Date.now(); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require([], function() { +function addCopyButtonCallbacks() { + for (const el of document.getElementsByTagName("pre")) { + const button = document.createElement("button"); + button.classList.add("copy-button", "fa-solid", "fa-copy"); + button.setAttribute("aria-label", "Copy this code block"); + button.setAttribute("title", "Copy"); + + el.appendChild(button); + + const success = function () { + button.classList.add("success", "fa-check"); + button.classList.remove("fa-copy"); + }; + + const failure = function () { + button.classList.add("error", "fa-xmark"); + button.classList.remove("fa-copy"); + }; + + button.addEventListener("click", function () { + copyToClipboard(el.innerText).then(success, failure); + + setTimeout(function () { + button.classList.add("fa-copy"); + button.classList.remove("success", "fa-check", "fa-xmark"); + }, 5000); + }); + } +} + +function copyToClipboard(text) { + // clipboard API is only available in secure contexts + if (window.navigator && window.navigator.clipboard) { + return window.navigator.clipboard.writeText(text); + } else { + return new Promise(function (resolve, reject) { + try { + const el = document.createElement("textarea"); + el.textContent = text; + el.style.position = "fixed"; + el.style.opacity = 0; + document.body.appendChild(el); + el.select(); + document.execCommand("copy"); + + resolve(); + } catch (err) { + reject(err); + } finally { + document.body.removeChild(el); + } + }); + } +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", addCopyButtonCallbacks); +} else { + addCopyButtonCallbacks(); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'headroom', 'headroom-jquery'], function($, Headroom) { + +// Manages the top navigation bar (hides it when the user starts scrolling down on the +// mobile). +window.Headroom = Headroom; // work around buggy module loading? +$(document).ready(function () { + $("#documenter .docs-navbar").headroom({ + tolerance: { up: 10, down: 10 }, + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +$(document).ready(function () { + let meta = $("div[data-docstringscollapsed]").data(); + + if (meta?.docstringscollapsed) { + $("#documenter-article-toggle-button").trigger({ + type: "click", + noToggleAnimation: true, + }); + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +/* +To get an in-depth about the thought process you can refer: https://hetarth02.hashnode.dev/series/gsoc + +PSEUDOCODE: + +Searching happens automatically as the user types or adjusts the selected filters. +To preserve responsiveness, as much as possible of the slow parts of the search are done +in a web worker. Searching and result generation are done in the worker, and filtering and +DOM updates are done in the main thread. The filters are in the main thread as they should +be very quick to apply. This lets filters be changed without re-searching with minisearch +(which is possible even if filtering is on the worker thread) and also lets filters be +changed _while_ the worker is searching and without message passing (neither of which are +possible if filtering is on the worker thread) + +SEARCH WORKER: + +Import minisearch + +Build index + +On message from main thread + run search + find the first 200 unique results from each category, and compute their divs for display + note that this is necessary and sufficient information for the main thread to find the + first 200 unique results from any given filter set + post results to main thread + +MAIN: + +Launch worker + +Declare nonconstant globals (worker_is_running, last_search_text, unfiltered_results) + +On text update + if worker is not running, launch_search() + +launch_search + set worker_is_running to true, set last_search_text to the search text + post the search query to worker + +on message from worker + if last_search_text is not the same as the text in the search field, + the latest search result is not reflective of the latest search query, so update again + launch_search() + otherwise + set worker_is_running to false + + regardless, display the new search results to the user + save the unfiltered_results as a global + update_search() + +on filter click + adjust the filter selection + update_search() + +update_search + apply search filters by looping through the unfiltered_results and finding the first 200 + unique results that match the filters + + Update the DOM +*/ + +/////// SEARCH WORKER /////// + +function worker_function(documenterSearchIndex, documenterBaseURL, filters) { + importScripts( + "https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min.js" + ); + + let data = documenterSearchIndex.map((x, key) => { + x["id"] = key; // minisearch requires a unique for each object + return x; + }); + + // list below is the lunr 2.1.3 list minus the intersect with names(Base) + // (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with) + // ideally we'd just filter the original list but it's not available as a variable + const stopWords = new Set([ + "a", + "able", + "about", + "across", + "after", + "almost", + "also", + "am", + "among", + "an", + "and", + "are", + "as", + "at", + "be", + "because", + "been", + "but", + "by", + "can", + "cannot", + "could", + "dear", + "did", + "does", + "either", + "ever", + "every", + "from", + "got", + "had", + "has", + "have", + "he", + "her", + "hers", + "him", + "his", + "how", + "however", + "i", + "if", + "into", + "it", + "its", + "just", + "least", + "like", + "likely", + "may", + "me", + "might", + "most", + "must", + "my", + "neither", + "no", + "nor", + "not", + "of", + "off", + "often", + "on", + "or", + "other", + "our", + "own", + "rather", + "said", + "say", + "says", + "she", + "should", + "since", + "so", + "some", + "than", + "that", + "the", + "their", + "them", + "then", + "there", + "these", + "they", + "this", + "tis", + "to", + "too", + "twas", + "us", + "wants", + "was", + "we", + "were", + "what", + "when", + "who", + "whom", + "why", + "will", + "would", + "yet", + "you", + "your", + ]); + + let index = new MiniSearch({ + fields: ["title", "text"], // fields to index for full-text search + storeFields: ["location", "title", "text", "category", "page"], // fields to return with results + processTerm: (term) => { + let word = stopWords.has(term) ? null : term; + if (word) { + // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names + word = word + .replace(/^[^a-zA-Z0-9@!]+/, "") + .replace(/[^a-zA-Z0-9@!]+$/, ""); + + word = word.toLowerCase(); + } + + return word ?? null; + }, + // add . as a separator, because otherwise "title": "Documenter.Anchors.add!", would not + // find anything if searching for "add!", only for the entire qualification + tokenize: (string) => string.split(/[\s\-\.]+/), + // options which will be applied during the search + searchOptions: { + prefix: true, + boost: { title: 100 }, + fuzzy: 2, + }, + }); + + index.addAll(data); + + /** + * Used to map characters to HTML entities. + * Refer: https://github.com/lodash/lodash/blob/main/src/escape.ts + */ + const htmlEscapes = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + }; + + /** + * Used to match HTML entities and HTML characters. + * Refer: https://github.com/lodash/lodash/blob/main/src/escape.ts + */ + const reUnescapedHtml = /[&<>"']/g; + const reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** + * Escape function from lodash + * Refer: https://github.com/lodash/lodash/blob/main/src/escape.ts + */ + function escape(string) { + return string && reHasUnescapedHtml.test(string) + ? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr]) + : string || ""; + } + + /** + * Make the result component given a minisearch result data object and the value + * of the search input as queryString. To view the result object structure, refer: + * https://lucaong.github.io/minisearch/modules/_minisearch_.html#searchresult + * + * @param {object} result + * @param {string} querystring + * @returns string + */ + function make_search_result(result, querystring) { + let search_divider = `
`; + let display_link = + result.location.slice(Math.max(0), Math.min(50, result.location.length)) + + (result.location.length > 30 ? "..." : ""); // To cut-off the link because it messes with the overflow of the whole div + + if (result.page !== "") { + display_link += ` (${result.page})`; + } + + let textindex = new RegExp(`${querystring}`, "i").exec(result.text); + let text = + textindex !== null + ? result.text.slice( + Math.max(textindex.index - 100, 0), + Math.min( + textindex.index + querystring.length + 100, + result.text.length + ) + ) + : ""; // cut-off text before and after from the match + + text = text.length ? escape(text) : ""; + + let display_result = text.length + ? "..." + + text.replace( + new RegExp(`${escape(querystring)}`, "i"), // For first occurrence + '$&' + ) + + "..." + : ""; // highlights the match + + let in_code = false; + if (!["page", "section"].includes(result.category.toLowerCase())) { + in_code = true; + } + + // We encode the full url to escape some special characters which can lead to broken links + let result_div = ` + +
+
${escape(result.title)}
+
${result.category}
+
+

+ ${display_result} +

+
+ ${display_link} +
+
+ ${search_divider} + `; + + return result_div; + } + + self.onmessage = function (e) { + let query = e.data; + let results = index.search(query, { + filter: (result) => { + // Only return relevant results + return result.score >= 1; + }, + }); + + // Pre-filter to deduplicate and limit to 200 per category to the extent + // possible without knowing what the filters are. + let filtered_results = []; + let counts = {}; + for (let filter of filters) { + counts[filter] = 0; + } + let present = {}; + + for (let result of results) { + cat = result.category; + cnt = counts[cat]; + if (cnt < 200) { + id = cat + "---" + result.location; + if (present[id]) { + continue; + } + present[id] = true; + filtered_results.push({ + location: result.location, + category: cat, + div: make_search_result(result, query), + }); + } + } + + postMessage(filtered_results); + }; +} + +// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! +const filters = [ + ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), +]; +const worker_str = + "(" + + worker_function.toString() + + ")(" + + JSON.stringify(documenterSearchIndex["docs"]) + + "," + + JSON.stringify(documenterBaseURL) + + "," + + JSON.stringify(filters) + + ")"; +const worker_blob = new Blob([worker_str], { type: "text/javascript" }); +const worker = new Worker(URL.createObjectURL(worker_blob)); + +/////// SEARCH MAIN /////// + +// Whether the worker is currently handling a search. This is a boolean +// as the worker only ever handles 1 or 0 searches at a time. +var worker_is_running = false; + +// The last search text that was sent to the worker. This is used to determine +// if the worker should be launched again when it reports back results. +var last_search_text = ""; + +// The results of the last search. This, in combination with the state of the filters +// in the DOM, is used compute the results to display on calls to update_search. +var unfiltered_results = []; + +// Which filter is currently selected +var selected_filter = ""; + +$(document).on("input", ".documenter-search-input", function (event) { + if (!worker_is_running) { + launch_search(); + } +}); + +function launch_search() { + worker_is_running = true; + last_search_text = $(".documenter-search-input").val(); + worker.postMessage(last_search_text); +} + +worker.onmessage = function (e) { + if (last_search_text !== $(".documenter-search-input").val()) { + launch_search(); + } else { + worker_is_running = false; + } + + unfiltered_results = e.data; + update_search(); +}; + +$(document).on("click", ".search-filter", function () { + if ($(this).hasClass("search-filter-selected")) { + selected_filter = ""; + } else { + selected_filter = $(this).text().toLowerCase(); + } + + // This updates search results and toggles classes for UI: + update_search(); +}); + +/** + * Make/Update the search component + */ +function update_search() { + let querystring = $(".documenter-search-input").val(); + + if (querystring.trim()) { + if (selected_filter == "") { + results = unfiltered_results; + } else { + results = unfiltered_results.filter((result) => { + return selected_filter == result.category.toLowerCase(); + }); + } + + let search_result_container = ``; + let modal_filters = make_modal_body_filters(); + let search_divider = `
`; + + if (results.length) { + let links = []; + let count = 0; + let search_results = ""; + + for (var i = 0, n = results.length; i < n && count < 200; ++i) { + let result = results[i]; + if (result.location && !links.includes(result.location)) { + search_results += result.div; + count++; + links.push(result.location); + } + } + + if (count == 1) { + count_str = "1 result"; + } else if (count == 200) { + count_str = "200+ results"; + } else { + count_str = count + " results"; + } + let result_count = `
${count_str}
`; + + search_result_container = ` +
+ ${modal_filters} + ${search_divider} + ${result_count} +
+ ${search_results} +
+
+ `; + } else { + search_result_container = ` +
+ ${modal_filters} + ${search_divider} +
0 result(s)
+
+
No result found!
+ `; + } + + if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").removeClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(search_result_container); + } else { + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(` +
Type something to get started!
+ `); + } +} + +/** + * Make the modal filter html + * + * @returns string + */ +function make_modal_body_filters() { + let str = filters + .map((val) => { + if (selected_filter == val.toLowerCase()) { + return `${val}`; + } else { + return `${val}`; + } + }) + .join(""); + + return ` +
+ Filters: + ${str} +
`; +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Modal settings dialog +$(document).ready(function () { + var settings = $("#documenter-settings"); + $("#documenter-settings-button").click(function () { + settings.toggleClass("is-active"); + }); + // Close the dialog if X is clicked + $("#documenter-settings button.delete").click(function () { + settings.removeClass("is-active"); + }); + // Close dialog if ESC is pressed + $(document).keyup(function (e) { + if (e.keyCode == 27) settings.removeClass("is-active"); + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +$(document).ready(function () { + let search_modal_header = ` + + `; + + let initial_search_body = ` +
Type something to get started!
+ `; + + let search_modal_footer = ` + + `; + + $(document.body).append( + ` + + ` + ); + + document.querySelector(".docs-search-query").addEventListener("click", () => { + openModal(); + }); + + document + .querySelector(".close-search-modal") + .addEventListener("click", () => { + closeModal(); + }); + + $(document).on("click", ".search-result-link", function () { + closeModal(); + }); + + document.addEventListener("keydown", (event) => { + if ((event.ctrlKey || event.metaKey) && event.key === "/") { + openModal(); + } else if (event.key === "Escape") { + closeModal(); + } + + return false; + }); + + // Functions to open and close a modal + function openModal() { + let searchModal = document.querySelector("#search-modal"); + + searchModal.classList.add("is-active"); + document.querySelector(".documenter-search-input").focus(); + } + + function closeModal() { + let searchModal = document.querySelector("#search-modal"); + let initial_search_body = ` +
Type something to get started!
+ `; + + searchModal.classList.remove("is-active"); + document.querySelector(".documenter-search-input").blur(); + + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".documenter-search-input").val(""); + $(".search-modal-card-body").html(initial_search_body); + } + + document + .querySelector("#search-modal .modal-background") + .addEventListener("click", () => { + closeModal(); + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Manages the showing and hiding of the sidebar. +$(document).ready(function () { + var sidebar = $("#documenter > .docs-sidebar"); + var sidebar_button = $("#documenter-sidebar-button"); + sidebar_button.click(function (ev) { + ev.preventDefault(); + sidebar.toggleClass("visible"); + if (sidebar.hasClass("visible")) { + // Makes sure that the current menu item is visible in the sidebar. + $("#documenter .docs-menu a.is-active").focus(); + } + }); + $("#documenter > .docs-main").bind("click", function (ev) { + if ($(ev.target).is(sidebar_button)) { + return; + } + if (sidebar.hasClass("visible")) { + sidebar.removeClass("visible"); + } + }); +}); + +// Resizes the package name / sitename in the sidebar if it is too wide. +// Inspired by: https://github.com/davatron5000/FitText.js +$(document).ready(function () { + e = $("#documenter .docs-autofit"); + function resize() { + var L = parseInt(e.css("max-width"), 10); + var L0 = e.width(); + if (L0 > L) { + var h0 = parseInt(e.css("font-size"), 10); + e.css("font-size", (L * h0) / L0); + // TODO: make sure it survives resizes? + } + } + // call once and then register events + resize(); + $(window).resize(resize); + $(window).on("orientationchange", resize); +}); + +// Scroll the navigation bar to the currently selected menu item +$(document).ready(function () { + var sidebar = $("#documenter .docs-menu").get(0); + var active = $("#documenter .docs-menu .is-active").get(0); + if (typeof active !== "undefined") { + sidebar.scrollTop = active.offsetTop - sidebar.offsetTop - 15; + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Theme picker setup +$(document).ready(function () { + // onchange callback + $("#documenter-themepicker").change(function themepick_callback(ev) { + var themename = $("#documenter-themepicker option:selected").attr("value"); + if (themename === "auto") { + // set_theme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); + window.localStorage.removeItem("documenter-theme"); + } else { + // set_theme(themename); + window.localStorage.setItem("documenter-theme", themename); + } + // We re-use the global function from themeswap.js to actually do the swapping. + set_theme_from_local_storage(); + }); + + // Make sure that the themepicker displays the correct theme when the theme is retrieved + // from localStorage + if (typeof window.localStorage !== "undefined") { + var theme = window.localStorage.getItem("documenter-theme"); + if (theme !== null) { + $("#documenter-themepicker option").each(function (i, e) { + e.selected = e.value === theme; + }); + } + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// update the version selector with info from the siteinfo.js and ../versions.js files +$(document).ready(function () { + // If the version selector is disabled with DOCUMENTER_VERSION_SELECTOR_DISABLED in the + // siteinfo.js file, we just return immediately and not display the version selector. + if ( + typeof DOCUMENTER_VERSION_SELECTOR_DISABLED === "boolean" && + DOCUMENTER_VERSION_SELECTOR_DISABLED + ) { + return; + } + + var version_selector = $("#documenter .docs-version-selector"); + var version_selector_select = $("#documenter .docs-version-selector select"); + + version_selector_select.change(function (x) { + target_href = version_selector_select + .children("option:selected") + .get(0).value; + window.location.href = target_href; + }); + + // add the current version to the selector based on siteinfo.js, but only if the selector is empty + if ( + typeof DOCUMENTER_CURRENT_VERSION !== "undefined" && + $("#version-selector > option").length == 0 + ) { + var option = $( + "" + ); + version_selector_select.append(option); + } + + if (typeof DOC_VERSIONS !== "undefined") { + var existing_versions = version_selector_select.children("option"); + var existing_versions_texts = existing_versions.map(function (i, x) { + return x.text; + }); + DOC_VERSIONS.forEach(function (each) { + var version_url = documenterBaseURL + "/../" + each + "/"; + var existing_id = $.inArray(each, existing_versions_texts); + // if not already in the version selector, add it as a new option, + // otherwise update the old option with the URL and enable it + if (existing_id == -1) { + var option = $( + "" + ); + version_selector_select.append(option); + } else { + var option = existing_versions[existing_id]; + option.value = version_url; + option.disabled = false; + } + }); + } + + // only show the version selector if the selector has been populated + if (version_selector_select.children("option").length > 0) { + version_selector.toggleClass("visible"); + } +}); + +}) diff --git a/v0.16.12/assets/favicon-16x16.png b/v0.16.12/assets/favicon-16x16.png new file mode 100644 index 000000000..2f92604d2 Binary files /dev/null and b/v0.16.12/assets/favicon-16x16.png differ diff --git a/v0.16.12/assets/favicon-32x32.png b/v0.16.12/assets/favicon-32x32.png new file mode 100644 index 000000000..4bdc6f8f2 Binary files /dev/null and b/v0.16.12/assets/favicon-32x32.png differ diff --git a/v0.16.12/assets/favicon-base.png b/v0.16.12/assets/favicon-base.png new file mode 100644 index 000000000..30fce9ee8 Binary files /dev/null and b/v0.16.12/assets/favicon-base.png differ diff --git a/v0.16.12/assets/favicon.ico b/v0.16.12/assets/favicon.ico new file mode 100644 index 000000000..c65bc60ba Binary files /dev/null and b/v0.16.12/assets/favicon.ico differ diff --git a/v0.16.12/assets/logo-500.png b/v0.16.12/assets/logo-500.png new file mode 100644 index 000000000..5969c6855 Binary files /dev/null and b/v0.16.12/assets/logo-500.png differ diff --git a/v0.16.12/assets/logo.png b/v0.16.12/assets/logo.png new file mode 100644 index 000000000..6549a2446 Binary files /dev/null and b/v0.16.12/assets/logo.png differ diff --git a/v0.16.12/assets/logo.svg b/v0.16.12/assets/logo.svg new file mode 100644 index 000000000..cf98c2ab1 --- /dev/null +++ b/v0.16.12/assets/logo.svg @@ -0,0 +1,913 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/assets/themes/documenter-dark.css b/v0.16.12/assets/themes/documenter-dark.css new file mode 100644 index 000000000..1d7170158 --- /dev/null +++ b/v0.16.12/assets/themes/documenter-dark.css @@ -0,0 +1,7 @@ +html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:.4em;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.5em - 1px);padding-left:calc(0.75em - 1px);padding-right:calc(0.75em - 1px);padding-top:calc(0.5em - 1px);position:relative;vertical-align:top}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus,html.theme--documenter-dark .pagination-ellipsis:focus,html.theme--documenter-dark .file-cta:focus,html.theme--documenter-dark .file-name:focus,html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .button:focus,html.theme--documenter-dark .is-focused.pagination-previous,html.theme--documenter-dark .is-focused.pagination-next,html.theme--documenter-dark .is-focused.pagination-link,html.theme--documenter-dark .is-focused.pagination-ellipsis,html.theme--documenter-dark .is-focused.file-cta,html.theme--documenter-dark .is-focused.file-name,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-focused.button,html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active,html.theme--documenter-dark .pagination-ellipsis:active,html.theme--documenter-dark .file-cta:active,html.theme--documenter-dark .file-name:active,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .button:active,html.theme--documenter-dark .is-active.pagination-previous,html.theme--documenter-dark .is-active.pagination-next,html.theme--documenter-dark .is-active.pagination-link,html.theme--documenter-dark .is-active.pagination-ellipsis,html.theme--documenter-dark .is-active.file-cta,html.theme--documenter-dark .is-active.file-name,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .is-active.button{outline:none}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-ellipsis[disabled],html.theme--documenter-dark .file-cta[disabled],html.theme--documenter-dark .file-name[disabled],html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark fieldset[disabled] .pagination-previous,fieldset[disabled] html.theme--documenter-dark .pagination-next,html.theme--documenter-dark fieldset[disabled] .pagination-next,fieldset[disabled] html.theme--documenter-dark .pagination-link,html.theme--documenter-dark fieldset[disabled] .pagination-link,fieldset[disabled] html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark fieldset[disabled] .pagination-ellipsis,fieldset[disabled] html.theme--documenter-dark .file-cta,html.theme--documenter-dark fieldset[disabled] .file-cta,fieldset[disabled] html.theme--documenter-dark .file-name,html.theme--documenter-dark fieldset[disabled] .file-name,fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark fieldset[disabled] .select select,html.theme--documenter-dark .select fieldset[disabled] select,html.theme--documenter-dark fieldset[disabled] .textarea,html.theme--documenter-dark fieldset[disabled] .input,html.theme--documenter-dark fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar fieldset[disabled] form.docs-search>input,fieldset[disabled] html.theme--documenter-dark .button,html.theme--documenter-dark fieldset[disabled] .button{cursor:not-allowed}html.theme--documenter-dark .tabs,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .breadcrumb,html.theme--documenter-dark .file,html.theme--documenter-dark .button,.is-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after,html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border:3px solid rgba(0,0,0,0);border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:0.625em;margin-top:-0.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:0.625em}html.theme--documenter-dark .admonition:not(:last-child),html.theme--documenter-dark .tabs:not(:last-child),html.theme--documenter-dark .pagination:not(:last-child),html.theme--documenter-dark .message:not(:last-child),html.theme--documenter-dark .level:not(:last-child),html.theme--documenter-dark .breadcrumb:not(:last-child),html.theme--documenter-dark .block:not(:last-child),html.theme--documenter-dark .title:not(:last-child),html.theme--documenter-dark .subtitle:not(:last-child),html.theme--documenter-dark .table-container:not(:last-child),html.theme--documenter-dark .table:not(:last-child),html.theme--documenter-dark .progress:not(:last-child),html.theme--documenter-dark .notification:not(:last-child),html.theme--documenter-dark .content:not(:last-child),html.theme--documenter-dark .box:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .modal-close,html.theme--documenter-dark .delete{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:none;position:relative;vertical-align:top;width:20px}html.theme--documenter-dark .modal-close::before,html.theme--documenter-dark .delete::before,html.theme--documenter-dark .modal-close::after,html.theme--documenter-dark .delete::after{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .modal-close::before,html.theme--documenter-dark .delete::before{height:2px;width:50%}html.theme--documenter-dark .modal-close::after,html.theme--documenter-dark .delete::after{height:50%;width:2px}html.theme--documenter-dark .modal-close:hover,html.theme--documenter-dark .delete:hover,html.theme--documenter-dark .modal-close:focus,html.theme--documenter-dark .delete:focus{background-color:rgba(10,10,10,0.3)}html.theme--documenter-dark .modal-close:active,html.theme--documenter-dark .delete:active{background-color:rgba(10,10,10,0.4)}html.theme--documenter-dark .is-small.modal-close,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.modal-close,html.theme--documenter-dark .is-small.delete,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.delete{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}html.theme--documenter-dark .is-medium.modal-close,html.theme--documenter-dark .is-medium.delete{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}html.theme--documenter-dark .is-large.modal-close,html.theme--documenter-dark .is-large.delete{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}html.theme--documenter-dark .control.is-loading::after,html.theme--documenter-dark .select.is-loading::after,html.theme--documenter-dark .loader,html.theme--documenter-dark .button.is-loading::after{animation:spinAround 500ms infinite linear;border:2px solid #dbdee0;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}html.theme--documenter-dark .hero-video,html.theme--documenter-dark .modal-background,html.theme--documenter-dark .modal,html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio,.is-overlay{bottom:0;left:0;position:absolute;right:0;top:0}html.theme--documenter-dark .navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}.has-text-white{color:#fff !important}a.has-text-white:hover,a.has-text-white:focus{color:#e6e6e6 !important}.has-background-white{background-color:#fff !important}.has-text-black{color:#0a0a0a !important}a.has-text-black:hover,a.has-text-black:focus{color:#000 !important}.has-background-black{background-color:#0a0a0a !important}.has-text-light{color:#ecf0f1 !important}a.has-text-light:hover,a.has-text-light:focus{color:#cfd9db !important}.has-background-light{background-color:#ecf0f1 !important}.has-text-dark{color:#282f2f !important}a.has-text-dark:hover,a.has-text-dark:focus{color:#111414 !important}.has-background-dark{background-color:#282f2f !important}.has-text-primary{color:#375a7f !important}a.has-text-primary:hover,a.has-text-primary:focus{color:#28415b !important}.has-background-primary{background-color:#375a7f !important}.has-text-primary-light{color:#f1f5f9 !important}a.has-text-primary-light:hover,a.has-text-primary-light:focus{color:#cddbe9 !important}.has-background-primary-light{background-color:#f1f5f9 !important}.has-text-primary-dark{color:#4d7eb2 !important}a.has-text-primary-dark:hover,a.has-text-primary-dark:focus{color:#7198c1 !important}.has-background-primary-dark{background-color:#4d7eb2 !important}.has-text-link{color:#1abc9c !important}a.has-text-link:hover,a.has-text-link:focus{color:#148f77 !important}.has-background-link{background-color:#1abc9c !important}.has-text-link-light{color:#edfdf9 !important}a.has-text-link-light:hover,a.has-text-link-light:focus{color:#c0f6ec !important}.has-background-link-light{background-color:#edfdf9 !important}.has-text-link-dark{color:#15987e !important}a.has-text-link-dark:hover,a.has-text-link-dark:focus{color:#1bc5a4 !important}.has-background-link-dark{background-color:#15987e !important}.has-text-info{color:#024c7d !important}a.has-text-info:hover,a.has-text-info:focus{color:#012d4b !important}.has-background-info{background-color:#024c7d !important}.has-text-info-light{color:#ebf7ff !important}a.has-text-info-light:hover,a.has-text-info-light:focus{color:#b9e2fe !important}.has-background-info-light{background-color:#ebf7ff !important}.has-text-info-dark{color:#0e9dfb !important}a.has-text-info-dark:hover,a.has-text-info-dark:focus{color:#40b1fc !important}.has-background-info-dark{background-color:#0e9dfb !important}.has-text-success{color:#008438 !important}a.has-text-success:hover,a.has-text-success:focus{color:#005122 !important}.has-background-success{background-color:#008438 !important}.has-text-success-light{color:#ebfff3 !important}a.has-text-success-light:hover,a.has-text-success-light:focus{color:#b8ffd6 !important}.has-background-success-light{background-color:#ebfff3 !important}.has-text-success-dark{color:#00eb64 !important}a.has-text-success-dark:hover,a.has-text-success-dark:focus{color:#1fff7e !important}.has-background-success-dark{background-color:#00eb64 !important}.has-text-warning{color:#ad8100 !important}a.has-text-warning:hover,a.has-text-warning:focus{color:#7a5b00 !important}.has-background-warning{background-color:#ad8100 !important}.has-text-warning-light{color:#fffaeb !important}a.has-text-warning-light:hover,a.has-text-warning-light:focus{color:#ffedb8 !important}.has-background-warning-light{background-color:#fffaeb !important}.has-text-warning-dark{color:#d19c00 !important}a.has-text-warning-dark:hover,a.has-text-warning-dark:focus{color:#ffbf05 !important}.has-background-warning-dark{background-color:#d19c00 !important}.has-text-danger{color:#9e1b0d !important}a.has-text-danger:hover,a.has-text-danger:focus{color:#6f1309 !important}.has-background-danger{background-color:#9e1b0d !important}.has-text-danger-light{color:#fdeeec !important}a.has-text-danger-light:hover,a.has-text-danger-light:focus{color:#fac3bd !important}.has-background-danger-light{background-color:#fdeeec !important}.has-text-danger-dark{color:#ec311d !important}a.has-text-danger-dark:hover,a.has-text-danger-dark:focus{color:#f05c4c !important}.has-background-danger-dark{background-color:#ec311d !important}.has-text-black-bis{color:#121212 !important}.has-background-black-bis{background-color:#121212 !important}.has-text-black-ter{color:#242424 !important}.has-background-black-ter{background-color:#242424 !important}.has-text-grey-darker{color:#282f2f !important}.has-background-grey-darker{background-color:#282f2f !important}.has-text-grey-dark{color:#343c3d !important}.has-background-grey-dark{background-color:#343c3d !important}.has-text-grey{color:#5e6d6f !important}.has-background-grey{background-color:#5e6d6f !important}.has-text-grey-light{color:#8c9b9d !important}.has-background-grey-light{background-color:#8c9b9d !important}.has-text-grey-lighter{color:#dbdee0 !important}.has-background-grey-lighter{background-color:#dbdee0 !important}.has-text-white-ter{color:#ecf0f1 !important}.has-background-white-ter{background-color:#ecf0f1 !important}.has-text-white-bis{color:#fafafa !important}.has-background-white-bis{background-color:#fafafa !important}.is-flex-direction-row{flex-direction:row !important}.is-flex-direction-row-reverse{flex-direction:row-reverse !important}.is-flex-direction-column{flex-direction:column !important}.is-flex-direction-column-reverse{flex-direction:column-reverse !important}.is-flex-wrap-nowrap{flex-wrap:nowrap !important}.is-flex-wrap-wrap{flex-wrap:wrap !important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse !important}.is-justify-content-flex-start{justify-content:flex-start !important}.is-justify-content-flex-end{justify-content:flex-end !important}.is-justify-content-center{justify-content:center !important}.is-justify-content-space-between{justify-content:space-between !important}.is-justify-content-space-around{justify-content:space-around !important}.is-justify-content-space-evenly{justify-content:space-evenly !important}.is-justify-content-start{justify-content:start !important}.is-justify-content-end{justify-content:end !important}.is-justify-content-left{justify-content:left !important}.is-justify-content-right{justify-content:right !important}.is-align-content-flex-start{align-content:flex-start !important}.is-align-content-flex-end{align-content:flex-end !important}.is-align-content-center{align-content:center !important}.is-align-content-space-between{align-content:space-between !important}.is-align-content-space-around{align-content:space-around !important}.is-align-content-space-evenly{align-content:space-evenly !important}.is-align-content-stretch{align-content:stretch !important}.is-align-content-start{align-content:start !important}.is-align-content-end{align-content:end !important}.is-align-content-baseline{align-content:baseline !important}.is-align-items-stretch{align-items:stretch !important}.is-align-items-flex-start{align-items:flex-start !important}.is-align-items-flex-end{align-items:flex-end !important}.is-align-items-center{align-items:center !important}.is-align-items-baseline{align-items:baseline !important}.is-align-items-start{align-items:start !important}.is-align-items-end{align-items:end !important}.is-align-items-self-start{align-items:self-start !important}.is-align-items-self-end{align-items:self-end !important}.is-align-self-auto{align-self:auto !important}.is-align-self-flex-start{align-self:flex-start !important}.is-align-self-flex-end{align-self:flex-end !important}.is-align-self-center{align-self:center !important}.is-align-self-baseline{align-self:baseline !important}.is-align-self-stretch{align-self:stretch !important}.is-flex-grow-0{flex-grow:0 !important}.is-flex-grow-1{flex-grow:1 !important}.is-flex-grow-2{flex-grow:2 !important}.is-flex-grow-3{flex-grow:3 !important}.is-flex-grow-4{flex-grow:4 !important}.is-flex-grow-5{flex-grow:5 !important}.is-flex-shrink-0{flex-shrink:0 !important}.is-flex-shrink-1{flex-shrink:1 !important}.is-flex-shrink-2{flex-shrink:2 !important}.is-flex-shrink-3{flex-shrink:3 !important}.is-flex-shrink-4{flex-shrink:4 !important}.is-flex-shrink-5{flex-shrink:5 !important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-clickable{cursor:pointer !important;pointer-events:all !important}.is-clipped{overflow:hidden !important}.is-relative{position:relative !important}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.m-0{margin:0 !important}.mt-0{margin-top:0 !important}.mr-0{margin-right:0 !important}.mb-0{margin-bottom:0 !important}.ml-0{margin-left:0 !important}.mx-0{margin-left:0 !important;margin-right:0 !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.m-1{margin:.25rem !important}.mt-1{margin-top:.25rem !important}.mr-1{margin-right:.25rem !important}.mb-1{margin-bottom:.25rem !important}.ml-1{margin-left:.25rem !important}.mx-1{margin-left:.25rem !important;margin-right:.25rem !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.m-2{margin:.5rem !important}.mt-2{margin-top:.5rem !important}.mr-2{margin-right:.5rem !important}.mb-2{margin-bottom:.5rem !important}.ml-2{margin-left:.5rem !important}.mx-2{margin-left:.5rem !important;margin-right:.5rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.m-3{margin:.75rem !important}.mt-3{margin-top:.75rem !important}.mr-3{margin-right:.75rem !important}.mb-3{margin-bottom:.75rem !important}.ml-3{margin-left:.75rem !important}.mx-3{margin-left:.75rem !important;margin-right:.75rem !important}.my-3{margin-top:.75rem !important;margin-bottom:.75rem !important}.m-4{margin:1rem !important}.mt-4{margin-top:1rem !important}.mr-4{margin-right:1rem !important}.mb-4{margin-bottom:1rem !important}.ml-4{margin-left:1rem !important}.mx-4{margin-left:1rem !important;margin-right:1rem !important}.my-4{margin-top:1rem !important;margin-bottom:1rem !important}.m-5{margin:1.5rem !important}.mt-5{margin-top:1.5rem !important}.mr-5{margin-right:1.5rem !important}.mb-5{margin-bottom:1.5rem !important}.ml-5{margin-left:1.5rem !important}.mx-5{margin-left:1.5rem !important;margin-right:1.5rem !important}.my-5{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.m-6{margin:3rem !important}.mt-6{margin-top:3rem !important}.mr-6{margin-right:3rem !important}.mb-6{margin-bottom:3rem !important}.ml-6{margin-left:3rem !important}.mx-6{margin-left:3rem !important;margin-right:3rem !important}.my-6{margin-top:3rem !important;margin-bottom:3rem !important}.m-auto{margin:auto !important}.mt-auto{margin-top:auto !important}.mr-auto{margin-right:auto !important}.mb-auto{margin-bottom:auto !important}.ml-auto{margin-left:auto !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.p-0{padding:0 !important}.pt-0{padding-top:0 !important}.pr-0{padding-right:0 !important}.pb-0{padding-bottom:0 !important}.pl-0{padding-left:0 !important}.px-0{padding-left:0 !important;padding-right:0 !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.p-1{padding:.25rem !important}.pt-1{padding-top:.25rem !important}.pr-1{padding-right:.25rem !important}.pb-1{padding-bottom:.25rem !important}.pl-1{padding-left:.25rem !important}.px-1{padding-left:.25rem !important;padding-right:.25rem !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.p-2{padding:.5rem !important}.pt-2{padding-top:.5rem !important}.pr-2{padding-right:.5rem !important}.pb-2{padding-bottom:.5rem !important}.pl-2{padding-left:.5rem !important}.px-2{padding-left:.5rem !important;padding-right:.5rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.p-3{padding:.75rem !important}.pt-3{padding-top:.75rem !important}.pr-3{padding-right:.75rem !important}.pb-3{padding-bottom:.75rem !important}.pl-3{padding-left:.75rem !important}.px-3{padding-left:.75rem !important;padding-right:.75rem !important}.py-3{padding-top:.75rem !important;padding-bottom:.75rem !important}.p-4{padding:1rem !important}.pt-4{padding-top:1rem !important}.pr-4{padding-right:1rem !important}.pb-4{padding-bottom:1rem !important}.pl-4{padding-left:1rem !important}.px-4{padding-left:1rem !important;padding-right:1rem !important}.py-4{padding-top:1rem !important;padding-bottom:1rem !important}.p-5{padding:1.5rem !important}.pt-5{padding-top:1.5rem !important}.pr-5{padding-right:1.5rem !important}.pb-5{padding-bottom:1.5rem !important}.pl-5{padding-left:1.5rem !important}.px-5{padding-left:1.5rem !important;padding-right:1.5rem !important}.py-5{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.p-6{padding:3rem !important}.pt-6{padding-top:3rem !important}.pr-6{padding-right:3rem !important}.pb-6{padding-bottom:3rem !important}.pl-6{padding-left:3rem !important}.px-6{padding-left:3rem !important;padding-right:3rem !important}.py-6{padding-top:3rem !important;padding-bottom:3rem !important}.p-auto{padding:auto !important}.pt-auto{padding-top:auto !important}.pr-auto{padding-right:auto !important}.pb-auto{padding-bottom:auto !important}.pl-auto{padding-left:auto !important}.px-auto{padding-left:auto !important;padding-right:auto !important}.py-auto{padding-top:auto !important;padding-bottom:auto !important}.is-size-1{font-size:3rem !important}.is-size-2{font-size:2.5rem !important}.is-size-3{font-size:2rem !important}.is-size-4{font-size:1.5rem !important}.is-size-5{font-size:1.25rem !important}.is-size-6{font-size:1rem !important}.is-size-7,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{font-size:.75rem !important}@media screen and (max-width: 768px){.is-size-1-mobile{font-size:3rem !important}.is-size-2-mobile{font-size:2.5rem !important}.is-size-3-mobile{font-size:2rem !important}.is-size-4-mobile{font-size:1.5rem !important}.is-size-5-mobile{font-size:1.25rem !important}.is-size-6-mobile{font-size:1rem !important}.is-size-7-mobile{font-size:.75rem !important}}@media screen and (min-width: 769px),print{.is-size-1-tablet{font-size:3rem !important}.is-size-2-tablet{font-size:2.5rem !important}.is-size-3-tablet{font-size:2rem !important}.is-size-4-tablet{font-size:1.5rem !important}.is-size-5-tablet{font-size:1.25rem !important}.is-size-6-tablet{font-size:1rem !important}.is-size-7-tablet{font-size:.75rem !important}}@media screen and (max-width: 1055px){.is-size-1-touch{font-size:3rem !important}.is-size-2-touch{font-size:2.5rem !important}.is-size-3-touch{font-size:2rem !important}.is-size-4-touch{font-size:1.5rem !important}.is-size-5-touch{font-size:1.25rem !important}.is-size-6-touch{font-size:1rem !important}.is-size-7-touch{font-size:.75rem !important}}@media screen and (min-width: 1056px){.is-size-1-desktop{font-size:3rem !important}.is-size-2-desktop{font-size:2.5rem !important}.is-size-3-desktop{font-size:2rem !important}.is-size-4-desktop{font-size:1.5rem !important}.is-size-5-desktop{font-size:1.25rem !important}.is-size-6-desktop{font-size:1rem !important}.is-size-7-desktop{font-size:.75rem !important}}@media screen and (min-width: 1216px){.is-size-1-widescreen{font-size:3rem !important}.is-size-2-widescreen{font-size:2.5rem !important}.is-size-3-widescreen{font-size:2rem !important}.is-size-4-widescreen{font-size:1.5rem !important}.is-size-5-widescreen{font-size:1.25rem !important}.is-size-6-widescreen{font-size:1rem !important}.is-size-7-widescreen{font-size:.75rem !important}}@media screen and (min-width: 1408px){.is-size-1-fullhd{font-size:3rem !important}.is-size-2-fullhd{font-size:2.5rem !important}.is-size-3-fullhd{font-size:2rem !important}.is-size-4-fullhd{font-size:1.5rem !important}.is-size-5-fullhd{font-size:1.25rem !important}.is-size-6-fullhd{font-size:1rem !important}.is-size-7-fullhd{font-size:.75rem !important}}.has-text-centered{text-align:center !important}.has-text-justified{text-align:justify !important}.has-text-left{text-align:left !important}.has-text-right{text-align:right !important}@media screen and (max-width: 768px){.has-text-centered-mobile{text-align:center !important}}@media screen and (min-width: 769px),print{.has-text-centered-tablet{text-align:center !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-centered-tablet-only{text-align:center !important}}@media screen and (max-width: 1055px){.has-text-centered-touch{text-align:center !important}}@media screen and (min-width: 1056px){.has-text-centered-desktop{text-align:center !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-centered-desktop-only{text-align:center !important}}@media screen and (min-width: 1216px){.has-text-centered-widescreen{text-align:center !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-centered-widescreen-only{text-align:center !important}}@media screen and (min-width: 1408px){.has-text-centered-fullhd{text-align:center !important}}@media screen and (max-width: 768px){.has-text-justified-mobile{text-align:justify !important}}@media screen and (min-width: 769px),print{.has-text-justified-tablet{text-align:justify !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-justified-tablet-only{text-align:justify !important}}@media screen and (max-width: 1055px){.has-text-justified-touch{text-align:justify !important}}@media screen and (min-width: 1056px){.has-text-justified-desktop{text-align:justify !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-justified-desktop-only{text-align:justify !important}}@media screen and (min-width: 1216px){.has-text-justified-widescreen{text-align:justify !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-justified-widescreen-only{text-align:justify !important}}@media screen and (min-width: 1408px){.has-text-justified-fullhd{text-align:justify !important}}@media screen and (max-width: 768px){.has-text-left-mobile{text-align:left !important}}@media screen and (min-width: 769px),print{.has-text-left-tablet{text-align:left !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-left-tablet-only{text-align:left !important}}@media screen and (max-width: 1055px){.has-text-left-touch{text-align:left !important}}@media screen and (min-width: 1056px){.has-text-left-desktop{text-align:left !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-left-desktop-only{text-align:left !important}}@media screen and (min-width: 1216px){.has-text-left-widescreen{text-align:left !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-left-widescreen-only{text-align:left !important}}@media screen and (min-width: 1408px){.has-text-left-fullhd{text-align:left !important}}@media screen and (max-width: 768px){.has-text-right-mobile{text-align:right !important}}@media screen and (min-width: 769px),print{.has-text-right-tablet{text-align:right !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-right-tablet-only{text-align:right !important}}@media screen and (max-width: 1055px){.has-text-right-touch{text-align:right !important}}@media screen and (min-width: 1056px){.has-text-right-desktop{text-align:right !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-right-desktop-only{text-align:right !important}}@media screen and (min-width: 1216px){.has-text-right-widescreen{text-align:right !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-right-widescreen-only{text-align:right !important}}@media screen and (min-width: 1408px){.has-text-right-fullhd{text-align:right !important}}.is-capitalized{text-transform:capitalize !important}.is-lowercase{text-transform:lowercase !important}.is-uppercase{text-transform:uppercase !important}.is-italic{font-style:italic !important}.is-underlined{text-decoration:underline !important}.has-text-weight-light{font-weight:300 !important}.has-text-weight-normal{font-weight:400 !important}.has-text-weight-medium{font-weight:500 !important}.has-text-weight-semibold{font-weight:600 !important}.has-text-weight-bold{font-weight:700 !important}.is-family-primary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-secondary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-sans-serif{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-monospace{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-family-code{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-block{display:block !important}@media screen and (max-width: 768px){.is-block-mobile{display:block !important}}@media screen and (min-width: 769px),print{.is-block-tablet{display:block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-block-tablet-only{display:block !important}}@media screen and (max-width: 1055px){.is-block-touch{display:block !important}}@media screen and (min-width: 1056px){.is-block-desktop{display:block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-block-desktop-only{display:block !important}}@media screen and (min-width: 1216px){.is-block-widescreen{display:block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-block-widescreen-only{display:block !important}}@media screen and (min-width: 1408px){.is-block-fullhd{display:block !important}}.is-flex{display:flex !important}@media screen and (max-width: 768px){.is-flex-mobile{display:flex !important}}@media screen and (min-width: 769px),print{.is-flex-tablet{display:flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-flex-tablet-only{display:flex !important}}@media screen and (max-width: 1055px){.is-flex-touch{display:flex !important}}@media screen and (min-width: 1056px){.is-flex-desktop{display:flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-flex-desktop-only{display:flex !important}}@media screen and (min-width: 1216px){.is-flex-widescreen{display:flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-flex-widescreen-only{display:flex !important}}@media screen and (min-width: 1408px){.is-flex-fullhd{display:flex !important}}.is-inline{display:inline !important}@media screen and (max-width: 768px){.is-inline-mobile{display:inline !important}}@media screen and (min-width: 769px),print{.is-inline-tablet{display:inline !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-tablet-only{display:inline !important}}@media screen and (max-width: 1055px){.is-inline-touch{display:inline !important}}@media screen and (min-width: 1056px){.is-inline-desktop{display:inline !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-desktop-only{display:inline !important}}@media screen and (min-width: 1216px){.is-inline-widescreen{display:inline !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-widescreen-only{display:inline !important}}@media screen and (min-width: 1408px){.is-inline-fullhd{display:inline !important}}.is-inline-block{display:inline-block !important}@media screen and (max-width: 768px){.is-inline-block-mobile{display:inline-block !important}}@media screen and (min-width: 769px),print{.is-inline-block-tablet{display:inline-block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-block-tablet-only{display:inline-block !important}}@media screen and (max-width: 1055px){.is-inline-block-touch{display:inline-block !important}}@media screen and (min-width: 1056px){.is-inline-block-desktop{display:inline-block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-block-desktop-only{display:inline-block !important}}@media screen and (min-width: 1216px){.is-inline-block-widescreen{display:inline-block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-block-widescreen-only{display:inline-block !important}}@media screen and (min-width: 1408px){.is-inline-block-fullhd{display:inline-block !important}}.is-inline-flex{display:inline-flex !important}@media screen and (max-width: 768px){.is-inline-flex-mobile{display:inline-flex !important}}@media screen and (min-width: 769px),print{.is-inline-flex-tablet{display:inline-flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-flex-tablet-only{display:inline-flex !important}}@media screen and (max-width: 1055px){.is-inline-flex-touch{display:inline-flex !important}}@media screen and (min-width: 1056px){.is-inline-flex-desktop{display:inline-flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-flex-desktop-only{display:inline-flex !important}}@media screen and (min-width: 1216px){.is-inline-flex-widescreen{display:inline-flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-flex-widescreen-only{display:inline-flex !important}}@media screen and (min-width: 1408px){.is-inline-flex-fullhd{display:inline-flex !important}}.is-hidden{display:none !important}.is-sr-only{border:none !important;clip:rect(0, 0, 0, 0) !important;height:0.01em !important;overflow:hidden !important;padding:0 !important;position:absolute !important;white-space:nowrap !important;width:0.01em !important}@media screen and (max-width: 768px){.is-hidden-mobile{display:none !important}}@media screen and (min-width: 769px),print{.is-hidden-tablet{display:none !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-hidden-tablet-only{display:none !important}}@media screen and (max-width: 1055px){.is-hidden-touch{display:none !important}}@media screen and (min-width: 1056px){.is-hidden-desktop{display:none !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-hidden-desktop-only{display:none !important}}@media screen and (min-width: 1216px){.is-hidden-widescreen{display:none !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-hidden-widescreen-only{display:none !important}}@media screen and (min-width: 1408px){.is-hidden-fullhd{display:none !important}}.is-invisible{visibility:hidden !important}@media screen and (max-width: 768px){.is-invisible-mobile{visibility:hidden !important}}@media screen and (min-width: 769px),print{.is-invisible-tablet{visibility:hidden !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-invisible-tablet-only{visibility:hidden !important}}@media screen and (max-width: 1055px){.is-invisible-touch{visibility:hidden !important}}@media screen and (min-width: 1056px){.is-invisible-desktop{visibility:hidden !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-invisible-desktop-only{visibility:hidden !important}}@media screen and (min-width: 1216px){.is-invisible-widescreen{visibility:hidden !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-invisible-widescreen-only{visibility:hidden !important}}@media screen and (min-width: 1408px){.is-invisible-fullhd{visibility:hidden !important}}html.theme--documenter-dark{/*! + Theme: a11y-dark + Author: @ericwbailey + Maintainer: @ericwbailey + + Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css +*/}html.theme--documenter-dark html{background-color:#1f2424;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark article,html.theme--documenter-dark aside,html.theme--documenter-dark figure,html.theme--documenter-dark footer,html.theme--documenter-dark header,html.theme--documenter-dark hgroup,html.theme--documenter-dark section{display:block}html.theme--documenter-dark body,html.theme--documenter-dark button,html.theme--documenter-dark input,html.theme--documenter-dark optgroup,html.theme--documenter-dark select,html.theme--documenter-dark textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}html.theme--documenter-dark code,html.theme--documenter-dark pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark body{color:#fff;font-size:1em;font-weight:400;line-height:1.5}html.theme--documenter-dark a{color:#1abc9c;cursor:pointer;text-decoration:none}html.theme--documenter-dark a strong{color:currentColor}html.theme--documenter-dark a:hover{color:#1dd2af}html.theme--documenter-dark code{background-color:rgba(255,255,255,0.05);color:#ececec;font-size:.875em;font-weight:normal;padding:.1em}html.theme--documenter-dark hr{background-color:#282f2f;border:none;display:block;height:2px;margin:1.5rem 0}html.theme--documenter-dark img{height:auto;max-width:100%}html.theme--documenter-dark input[type="checkbox"],html.theme--documenter-dark input[type="radio"]{vertical-align:baseline}html.theme--documenter-dark small{font-size:.875em}html.theme--documenter-dark span{font-style:inherit;font-weight:inherit}html.theme--documenter-dark strong{color:#f2f2f2;font-weight:700}html.theme--documenter-dark fieldset{border:none}html.theme--documenter-dark pre{-webkit-overflow-scrolling:touch;background-color:#282f2f;color:#fff;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}html.theme--documenter-dark pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}html.theme--documenter-dark table td,html.theme--documenter-dark table th{vertical-align:top}html.theme--documenter-dark table td:not([align]),html.theme--documenter-dark table th:not([align]){text-align:inherit}html.theme--documenter-dark table th{color:#f2f2f2}html.theme--documenter-dark .box{background-color:#343c3d;border-radius:8px;box-shadow:none;color:#fff;display:block;padding:1.25rem}html.theme--documenter-dark a.box:hover,html.theme--documenter-dark a.box:focus{box-shadow:0 0.5em 1em -0.125em rgba(10,10,10,0.1),0 0 0 1px #1abc9c}html.theme--documenter-dark a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #1abc9c}html.theme--documenter-dark .button{background-color:#282f2f;border-color:#4c5759;border-width:1px;color:#375a7f;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 1px);text-align:center;white-space:nowrap}html.theme--documenter-dark .button strong{color:inherit}html.theme--documenter-dark .button .icon,html.theme--documenter-dark .button .icon.is-small,html.theme--documenter-dark .button #documenter .docs-sidebar form.docs-search>input.icon,html.theme--documenter-dark #documenter .docs-sidebar .button form.docs-search>input.icon,html.theme--documenter-dark .button .icon.is-medium,html.theme--documenter-dark .button .icon.is-large{height:1.5em;width:1.5em}html.theme--documenter-dark .button .icon:first-child:not(:last-child){margin-left:calc(-0.5em - 1px);margin-right:.25em}html.theme--documenter-dark .button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button:hover,html.theme--documenter-dark .button.is-hovered{border-color:#8c9b9d;color:#f2f2f2}html.theme--documenter-dark .button:focus,html.theme--documenter-dark .button.is-focused{border-color:#8c9b9d;color:#17a689}html.theme--documenter-dark .button:focus:not(:active),html.theme--documenter-dark .button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button:active,html.theme--documenter-dark .button.is-active{border-color:#343c3d;color:#f2f2f2}html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;color:#fff;text-decoration:underline}html.theme--documenter-dark .button.is-text:hover,html.theme--documenter-dark .button.is-text.is-hovered,html.theme--documenter-dark .button.is-text:focus,html.theme--documenter-dark .button.is-text.is-focused{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .button.is-text:active,html.theme--documenter-dark .button.is-text.is-active{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .button.is-text[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-ghost{background:none;border-color:rgba(0,0,0,0);color:#1abc9c;text-decoration:none}html.theme--documenter-dark .button.is-ghost:hover,html.theme--documenter-dark .button.is-ghost.is-hovered{color:#1abc9c;text-decoration:underline}html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:hover,html.theme--documenter-dark .button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus,html.theme--documenter-dark .button.is-white.is-focused{border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus:not(:active),html.theme--documenter-dark .button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-hovered{background-color:#000}html.theme--documenter-dark .button.is-white.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-white.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:hover,html.theme--documenter-dark .button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus,html.theme--documenter-dark .button.is-black.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus:not(:active),html.theme--documenter-dark .button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-black.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:hover,html.theme--documenter-dark .button.is-light.is-hovered{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus,html.theme--documenter-dark .button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus:not(:active),html.theme--documenter-dark .button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light.is-active{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:#ecf0f1;box-shadow:none}html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-outlined.is-focused{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-dark,html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover,html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus:not(:active),html.theme--documenter-dark .content kbd.button:focus:not(:active),html.theme--documenter-dark .button.is-dark.is-focused:not(:active),html.theme--documenter-dark .content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark[disabled],html.theme--documenter-dark .content kbd.button[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark,fieldset[disabled] html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:#282f2f;box-shadow:none}html.theme--documenter-dark .button.is-dark.is-inverted,html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted:hover,html.theme--documenter-dark .content kbd.button.is-inverted:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-dark.is-inverted[disabled],html.theme--documenter-dark .content kbd.button.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-loading::after,html.theme--documenter-dark .content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined,html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-outlined.is-focused{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-focused{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus:not(:active),html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus:not(:active),html.theme--documenter-dark .button.is-primary.is-focused:not(:active),html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary[disabled],html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;box-shadow:none}html.theme--documenter-dark .button.is-primary.is-inverted,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}html.theme--documenter-dark .button.is-primary.is-inverted[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:hover,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-light.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e8eef5;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:active,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-light.is-active,html.theme--documenter-dark .docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#dfe8f1;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:hover,html.theme--documenter-dark .button.is-link.is-hovered{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus,html.theme--documenter-dark .button.is-link.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus:not(:active),html.theme--documenter-dark .button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link.is-active{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:#1abc9c;box-shadow:none}html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-link.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-outlined.is-focused{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:hover,html.theme--documenter-dark .button.is-link.is-light.is-hovered{background-color:#e2fbf6;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:active,html.theme--documenter-dark .button.is-link.is-light.is-active{background-color:#d7f9f3;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:hover,html.theme--documenter-dark .button.is-info.is-hovered{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus,html.theme--documenter-dark .button.is-info.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus:not(:active),html.theme--documenter-dark .button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info.is-active{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:#024c7d;box-shadow:none}html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-info.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;color:#024c7d}html.theme--documenter-dark .button.is-info.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-outlined.is-focused{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:hover,html.theme--documenter-dark .button.is-info.is-light.is-hovered{background-color:#def2fe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:active,html.theme--documenter-dark .button.is-info.is-light.is-active{background-color:#d2edfe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:hover,html.theme--documenter-dark .button.is-success.is-hovered{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus,html.theme--documenter-dark .button.is-success.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus:not(:active),html.theme--documenter-dark .button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success.is-active{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:#008438;box-shadow:none}html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-success.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;color:#008438}html.theme--documenter-dark .button.is-success.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-outlined.is-focused{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:hover,html.theme--documenter-dark .button.is-success.is-light.is-hovered{background-color:#deffec;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:active,html.theme--documenter-dark .button.is-success.is-light.is-active{background-color:#d1ffe5;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:hover,html.theme--documenter-dark .button.is-warning.is-hovered{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus,html.theme--documenter-dark .button.is-warning.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus:not(:active),html.theme--documenter-dark .button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning.is-active{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:#ad8100;box-shadow:none}html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-warning.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-outlined.is-focused{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-focused{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:hover,html.theme--documenter-dark .button.is-warning.is-light.is-hovered{background-color:#fff7de;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:active,html.theme--documenter-dark .button.is-warning.is-light.is-active{background-color:#fff3d1;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:hover,html.theme--documenter-dark .button.is-danger.is-hovered{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus,html.theme--documenter-dark .button.is-danger.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus:not(:active),html.theme--documenter-dark .button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger.is-active{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;box-shadow:none}html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-danger.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-outlined.is-focused{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:hover,html.theme--documenter-dark .button.is-danger.is-light.is-hovered{background-color:#fce3e0;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:active,html.theme--documenter-dark .button.is-danger.is-light.is-active{background-color:#fcd8d5;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}html.theme--documenter-dark .button.is-small:not(.is-rounded),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:3px}html.theme--documenter-dark .button.is-normal{font-size:1rem}html.theme--documenter-dark .button.is-medium{font-size:1.25rem}html.theme--documenter-dark .button.is-large{font-size:1.5rem}html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .button{background-color:#8c9b9d;border-color:#5e6d6f;box-shadow:none;opacity:.5}html.theme--documenter-dark .button.is-fullwidth{display:flex;width:100%}html.theme--documenter-dark .button.is-loading{color:transparent !important;pointer-events:none}html.theme--documenter-dark .button.is-loading::after{position:absolute;left:calc(50% - (1em * 0.5));top:calc(50% - (1em * 0.5));position:absolute !important}html.theme--documenter-dark .button.is-static{background-color:#282f2f;border-color:#5e6d6f;color:#dbdee0;box-shadow:none;pointer-events:none}html.theme--documenter-dark .button.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{border-radius:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}html.theme--documenter-dark .buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .buttons .button{margin-bottom:0.5rem}html.theme--documenter-dark .buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}html.theme--documenter-dark .buttons:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .buttons:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:3px}html.theme--documenter-dark .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}html.theme--documenter-dark .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}html.theme--documenter-dark .buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}html.theme--documenter-dark .buttons.has-addons .button:last-child{margin-right:0}html.theme--documenter-dark .buttons.has-addons .button:hover,html.theme--documenter-dark .buttons.has-addons .button.is-hovered{z-index:2}html.theme--documenter-dark .buttons.has-addons .button:focus,html.theme--documenter-dark .buttons.has-addons .button.is-focused,html.theme--documenter-dark .buttons.has-addons .button:active,html.theme--documenter-dark .buttons.has-addons .button.is-active,html.theme--documenter-dark .buttons.has-addons .button.is-selected{z-index:3}html.theme--documenter-dark .buttons.has-addons .button:focus:hover,html.theme--documenter-dark .buttons.has-addons .button.is-focused:hover,html.theme--documenter-dark .buttons.has-addons .button:active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-selected:hover{z-index:4}html.theme--documenter-dark .buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .buttons.is-centered{justify-content:center}html.theme--documenter-dark .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}html.theme--documenter-dark .buttons.is-right{justify-content:flex-end}html.theme--documenter-dark .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:1rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1.25rem}}html.theme--documenter-dark .container{flex-grow:1;margin:0 auto;position:relative;width:auto}html.theme--documenter-dark .container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){html.theme--documenter-dark .container{max-width:992px}}@media screen and (max-width: 1215px){html.theme--documenter-dark .container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){html.theme--documenter-dark .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){html.theme--documenter-dark .container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){html.theme--documenter-dark .container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}html.theme--documenter-dark .content li+li{margin-top:0.25em}html.theme--documenter-dark .content p:not(:last-child),html.theme--documenter-dark .content dl:not(:last-child),html.theme--documenter-dark .content ol:not(:last-child),html.theme--documenter-dark .content ul:not(:last-child),html.theme--documenter-dark .content blockquote:not(:last-child),html.theme--documenter-dark .content pre:not(:last-child),html.theme--documenter-dark .content table:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .content h1,html.theme--documenter-dark .content h2,html.theme--documenter-dark .content h3,html.theme--documenter-dark .content h4,html.theme--documenter-dark .content h5,html.theme--documenter-dark .content h6{color:#f2f2f2;font-weight:600;line-height:1.125}html.theme--documenter-dark .content h1{font-size:2em;margin-bottom:0.5em}html.theme--documenter-dark .content h1:not(:first-child){margin-top:1em}html.theme--documenter-dark .content h2{font-size:1.75em;margin-bottom:0.5714em}html.theme--documenter-dark .content h2:not(:first-child){margin-top:1.1428em}html.theme--documenter-dark .content h3{font-size:1.5em;margin-bottom:0.6666em}html.theme--documenter-dark .content h3:not(:first-child){margin-top:1.3333em}html.theme--documenter-dark .content h4{font-size:1.25em;margin-bottom:0.8em}html.theme--documenter-dark .content h5{font-size:1.125em;margin-bottom:0.8888em}html.theme--documenter-dark .content h6{font-size:1em;margin-bottom:1em}html.theme--documenter-dark .content blockquote{background-color:#282f2f;border-left:5px solid #5e6d6f;padding:1.25em 1.5em}html.theme--documenter-dark .content ol{list-style-position:outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ol:not([type]){list-style-type:decimal}html.theme--documenter-dark .content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}html.theme--documenter-dark .content ol.is-lower-roman:not([type]){list-style-type:lower-roman}html.theme--documenter-dark .content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}html.theme--documenter-dark .content ol.is-upper-roman:not([type]){list-style-type:upper-roman}html.theme--documenter-dark .content ul{list-style:disc outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ul ul{list-style-type:circle;margin-top:0.5em}html.theme--documenter-dark .content ul ul ul{list-style-type:square}html.theme--documenter-dark .content dd{margin-left:2em}html.theme--documenter-dark .content figure{margin-left:2em;margin-right:2em;text-align:center}html.theme--documenter-dark .content figure:not(:first-child){margin-top:2em}html.theme--documenter-dark .content figure:not(:last-child){margin-bottom:2em}html.theme--documenter-dark .content figure img{display:inline-block}html.theme--documenter-dark .content figure figcaption{font-style:italic}html.theme--documenter-dark .content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}html.theme--documenter-dark .content sup,html.theme--documenter-dark .content sub{font-size:75%}html.theme--documenter-dark .content table{width:100%}html.theme--documenter-dark .content table td,html.theme--documenter-dark .content table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .content table th{color:#f2f2f2}html.theme--documenter-dark .content table th:not([align]){text-align:inherit}html.theme--documenter-dark .content table thead td,html.theme--documenter-dark .content table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .content table tfoot td,html.theme--documenter-dark .content table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .content table tbody tr:last-child td,html.theme--documenter-dark .content table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .content .tabs li+li{margin-top:0}html.theme--documenter-dark .content.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}html.theme--documenter-dark .content.is-normal{font-size:1rem}html.theme--documenter-dark .content.is-medium{font-size:1.25rem}html.theme--documenter-dark .content.is-large{font-size:1.5rem}html.theme--documenter-dark .icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}html.theme--documenter-dark .icon.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}html.theme--documenter-dark .icon.is-medium{height:2rem;width:2rem}html.theme--documenter-dark .icon.is-large{height:3rem;width:3rem}html.theme--documenter-dark .icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}html.theme--documenter-dark .icon-text .icon{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .icon-text .icon:not(:last-child){margin-right:.25em}html.theme--documenter-dark .icon-text .icon:not(:first-child){margin-left:.25em}html.theme--documenter-dark div.icon-text{display:flex}html.theme--documenter-dark .image,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{display:block;position:relative}html.theme--documenter-dark .image img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}html.theme--documenter-dark .image img.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:9999px}html.theme--documenter-dark .image.is-fullwidth,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}html.theme--documenter-dark .image.is-square,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square,html.theme--documenter-dark .image.is-1by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}html.theme--documenter-dark .image.is-5by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}html.theme--documenter-dark .image.is-4by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}html.theme--documenter-dark .image.is-3by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}html.theme--documenter-dark .image.is-5by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}html.theme--documenter-dark .image.is-16by9,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}html.theme--documenter-dark .image.is-2by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}html.theme--documenter-dark .image.is-3by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}html.theme--documenter-dark .image.is-4by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}html.theme--documenter-dark .image.is-3by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}html.theme--documenter-dark .image.is-2by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}html.theme--documenter-dark .image.is-3by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}html.theme--documenter-dark .image.is-9by16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}html.theme--documenter-dark .image.is-1by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}html.theme--documenter-dark .image.is-1by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}html.theme--documenter-dark .image.is-16x16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}html.theme--documenter-dark .image.is-24x24,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}html.theme--documenter-dark .image.is-32x32,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}html.theme--documenter-dark .image.is-48x48,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}html.theme--documenter-dark .image.is-64x64,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}html.theme--documenter-dark .image.is-96x96,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}html.theme--documenter-dark .image.is-128x128,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}html.theme--documenter-dark .notification{background-color:#282f2f;border-radius:.4em;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}html.theme--documenter-dark .notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .notification strong{color:currentColor}html.theme--documenter-dark .notification code,html.theme--documenter-dark .notification pre{background:#fff}html.theme--documenter-dark .notification pre code{background:transparent}html.theme--documenter-dark .notification>.delete{right:.5rem;position:absolute;top:0.5rem}html.theme--documenter-dark .notification .title,html.theme--documenter-dark .notification .subtitle,html.theme--documenter-dark .notification .content{color:currentColor}html.theme--documenter-dark .notification.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .notification.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .notification.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .notification.is-dark,html.theme--documenter-dark .content kbd.notification{background-color:#282f2f;color:#fff}html.theme--documenter-dark .notification.is-primary,html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .notification.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.notification.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .notification.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .notification.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .notification.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .notification.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .notification.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .notification.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .notification.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .notification.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .notification.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .notification.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}html.theme--documenter-dark .progress::-webkit-progress-bar{background-color:#343c3d}html.theme--documenter-dark .progress::-webkit-progress-value{background-color:#dbdee0}html.theme--documenter-dark .progress::-moz-progress-bar{background-color:#dbdee0}html.theme--documenter-dark .progress::-ms-fill{background-color:#dbdee0;border:none}html.theme--documenter-dark .progress.is-white::-webkit-progress-value{background-color:#fff}html.theme--documenter-dark .progress.is-white::-moz-progress-bar{background-color:#fff}html.theme--documenter-dark .progress.is-white::-ms-fill{background-color:#fff}html.theme--documenter-dark .progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-black::-webkit-progress-value{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-moz-progress-bar{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-ms-fill{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-light::-webkit-progress-value{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-moz-progress-bar{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-ms-fill{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light:indeterminate{background-image:linear-gradient(to right, #ecf0f1 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-dark::-webkit-progress-value,html.theme--documenter-dark .content kbd.progress::-webkit-progress-value{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-moz-progress-bar,html.theme--documenter-dark .content kbd.progress::-moz-progress-bar{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-ms-fill,html.theme--documenter-dark .content kbd.progress::-ms-fill{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark:indeterminate,html.theme--documenter-dark .content kbd.progress:indeterminate{background-image:linear-gradient(to right, #282f2f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-primary::-webkit-progress-value,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-moz-progress-bar,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-ms-fill,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary:indeterminate,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #375a7f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-link::-webkit-progress-value{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-moz-progress-bar{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-ms-fill{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link:indeterminate{background-image:linear-gradient(to right, #1abc9c 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-info::-webkit-progress-value{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-moz-progress-bar{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-ms-fill{background-color:#024c7d}html.theme--documenter-dark .progress.is-info:indeterminate{background-image:linear-gradient(to right, #024c7d 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-success::-webkit-progress-value{background-color:#008438}html.theme--documenter-dark .progress.is-success::-moz-progress-bar{background-color:#008438}html.theme--documenter-dark .progress.is-success::-ms-fill{background-color:#008438}html.theme--documenter-dark .progress.is-success:indeterminate{background-image:linear-gradient(to right, #008438 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-warning::-webkit-progress-value{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-moz-progress-bar{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-ms-fill{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ad8100 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-danger::-webkit-progress-value{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-moz-progress-bar{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-ms-fill{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger:indeterminate{background-image:linear-gradient(to right, #9e1b0d 30%, #343c3d 30%)}html.theme--documenter-dark .progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#343c3d;background-image:linear-gradient(to right, #fff 30%, #343c3d 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}html.theme--documenter-dark .progress:indeterminate::-webkit-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-moz-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-ms-fill{animation-name:none}html.theme--documenter-dark .progress.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}html.theme--documenter-dark .progress.is-medium{height:1.25rem}html.theme--documenter-dark .progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}html.theme--documenter-dark .table{background-color:#343c3d;color:#fff}html.theme--documenter-dark .table td,html.theme--documenter-dark .table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .table td.is-white,html.theme--documenter-dark .table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .table td.is-black,html.theme--documenter-dark .table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .table td.is-light,html.theme--documenter-dark .table th.is-light{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .table td.is-dark,html.theme--documenter-dark .table th.is-dark{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .table td.is-primary,html.theme--documenter-dark .table th.is-primary{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-link,html.theme--documenter-dark .table th.is-link{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .table td.is-info,html.theme--documenter-dark .table th.is-info{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .table td.is-success,html.theme--documenter-dark .table th.is-success{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .table td.is-warning,html.theme--documenter-dark .table th.is-warning{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .table td.is-danger,html.theme--documenter-dark .table th.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .table td.is-narrow,html.theme--documenter-dark .table th.is-narrow{white-space:nowrap;width:1%}html.theme--documenter-dark .table td.is-selected,html.theme--documenter-dark .table th.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-selected a,html.theme--documenter-dark .table td.is-selected strong,html.theme--documenter-dark .table th.is-selected a,html.theme--documenter-dark .table th.is-selected strong{color:currentColor}html.theme--documenter-dark .table td.is-vcentered,html.theme--documenter-dark .table th.is-vcentered{vertical-align:middle}html.theme--documenter-dark .table th{color:#f2f2f2}html.theme--documenter-dark .table th:not([align]){text-align:left}html.theme--documenter-dark .table tr.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table tr.is-selected a,html.theme--documenter-dark .table tr.is-selected strong{color:currentColor}html.theme--documenter-dark .table tr.is-selected td,html.theme--documenter-dark .table tr.is-selected th{border-color:#fff;color:currentColor}html.theme--documenter-dark .table thead{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table thead td,html.theme--documenter-dark .table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .table tfoot{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tfoot td,html.theme--documenter-dark .table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .table tbody{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tbody tr:last-child td,html.theme--documenter-dark .table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .table.is-bordered td,html.theme--documenter-dark .table.is-bordered th{border-width:1px}html.theme--documenter-dark .table.is-bordered tr:last-child td,html.theme--documenter-dark .table.is-bordered tr:last-child th{border-bottom-width:1px}html.theme--documenter-dark .table.is-fullwidth{width:100%}html.theme--documenter-dark .table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#2d3435}html.theme--documenter-dark .table.is-narrow td,html.theme--documenter-dark .table.is-narrow th{padding:0.25em 0.5em}html.theme--documenter-dark .table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#282f2f}html.theme--documenter-dark .table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}html.theme--documenter-dark .tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .tags .tag,html.theme--documenter-dark .tags .content kbd,html.theme--documenter-dark .content .tags kbd,html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}html.theme--documenter-dark .tags .tag:not(:last-child),html.theme--documenter-dark .tags .content kbd:not(:last-child),html.theme--documenter-dark .content .tags kbd:not(:last-child),html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:.5rem}html.theme--documenter-dark .tags:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .tags:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .tags.are-medium .tag:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .content kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .content .tags.are-medium kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}html.theme--documenter-dark .tags.are-large .tag:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .content kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .content .tags.are-large kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}html.theme--documenter-dark .tags.is-centered{justify-content:center}html.theme--documenter-dark .tags.is-centered .tag,html.theme--documenter-dark .tags.is-centered .content kbd,html.theme--documenter-dark .content .tags.is-centered kbd,html.theme--documenter-dark .tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}html.theme--documenter-dark .tags.is-right{justify-content:flex-end}html.theme--documenter-dark .tags.is-right .tag:not(:first-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:first-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}html.theme--documenter-dark .tags.is-right .tag:not(:last-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:last-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}html.theme--documenter-dark .tags.has-addons .tag,html.theme--documenter-dark .tags.has-addons .content kbd,html.theme--documenter-dark .content .tags.has-addons kbd,html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}html.theme--documenter-dark .tags.has-addons .tag:not(:first-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:first-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}html.theme--documenter-dark .tags.has-addons .tag:not(:last-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:last-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}html.theme--documenter-dark .tag:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#282f2f;border-radius:.4em;color:#fff;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}html.theme--documenter-dark .tag:not(body) .delete,html.theme--documenter-dark .content kbd:not(body) .delete,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}html.theme--documenter-dark .tag.is-white:not(body),html.theme--documenter-dark .content kbd.is-white:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .tag.is-black:not(body),html.theme--documenter-dark .content kbd.is-black:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .tag.is-light:not(body),html.theme--documenter-dark .content kbd.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .tag.is-dark:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-dark:not(body),html.theme--documenter-dark .content .docstring>section>kbd:not(body){background-color:#282f2f;color:#fff}html.theme--documenter-dark .tag.is-primary:not(body),html.theme--documenter-dark .content kbd.is-primary:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){background-color:#375a7f;color:#fff}html.theme--documenter-dark .tag.is-primary.is-light:not(body),html.theme--documenter-dark .content kbd.is-primary.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .tag.is-link:not(body),html.theme--documenter-dark .content kbd.is-link:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#1abc9c;color:#fff}html.theme--documenter-dark .tag.is-link.is-light:not(body),html.theme--documenter-dark .content kbd.is-link.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .tag.is-info:not(body),html.theme--documenter-dark .content kbd.is-info:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#024c7d;color:#fff}html.theme--documenter-dark .tag.is-info.is-light:not(body),html.theme--documenter-dark .content kbd.is-info.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .tag.is-success:not(body),html.theme--documenter-dark .content kbd.is-success:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#008438;color:#fff}html.theme--documenter-dark .tag.is-success.is-light:not(body),html.theme--documenter-dark .content kbd.is-success.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .tag.is-warning:not(body),html.theme--documenter-dark .content kbd.is-warning:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ad8100;color:#fff}html.theme--documenter-dark .tag.is-warning.is-light:not(body),html.theme--documenter-dark .content kbd.is-warning.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .tag.is-danger:not(body),html.theme--documenter-dark .content kbd.is-danger:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .tag.is-danger.is-light:not(body),html.theme--documenter-dark .content kbd.is-danger.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .tag.is-normal:not(body),html.theme--documenter-dark .content kbd.is-normal:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}html.theme--documenter-dark .tag.is-medium:not(body),html.theme--documenter-dark .content kbd.is-medium:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}html.theme--documenter-dark .tag.is-large:not(body),html.theme--documenter-dark .content kbd.is-large:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}html.theme--documenter-dark .tag:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .content kbd:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}html.theme--documenter-dark .tag:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .content kbd:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}html.theme--documenter-dark .tag:not(body) .icon:first-child:last-child,html.theme--documenter-dark .content kbd:not(body) .icon:first-child:last-child,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}html.theme--documenter-dark .tag.is-delete:not(body),html.theme--documenter-dark .content kbd.is-delete:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before,html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}html.theme--documenter-dark .tag.is-delete:not(body):hover,html.theme--documenter-dark .content kbd.is-delete:not(body):hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):hover,html.theme--documenter-dark .tag.is-delete:not(body):focus,html.theme--documenter-dark .content kbd.is-delete:not(body):focus,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#1d2122}html.theme--documenter-dark .tag.is-delete:not(body):active,html.theme--documenter-dark .content kbd.is-delete:not(body):active,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#111414}html.theme--documenter-dark .tag.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:not(body),html.theme--documenter-dark .content kbd.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:9999px}html.theme--documenter-dark a.tag:hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:hover{text-decoration:underline}html.theme--documenter-dark .title,html.theme--documenter-dark .subtitle{word-break:break-word}html.theme--documenter-dark .title em,html.theme--documenter-dark .title span,html.theme--documenter-dark .subtitle em,html.theme--documenter-dark .subtitle span{font-weight:inherit}html.theme--documenter-dark .title sub,html.theme--documenter-dark .subtitle sub{font-size:.75em}html.theme--documenter-dark .title sup,html.theme--documenter-dark .subtitle sup{font-size:.75em}html.theme--documenter-dark .title .tag,html.theme--documenter-dark .title .content kbd,html.theme--documenter-dark .content .title kbd,html.theme--documenter-dark .title .docstring>section>a.docs-sourcelink,html.theme--documenter-dark .subtitle .tag,html.theme--documenter-dark .subtitle .content kbd,html.theme--documenter-dark .content .subtitle kbd,html.theme--documenter-dark .subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}html.theme--documenter-dark .title{color:#fff;font-size:2rem;font-weight:500;line-height:1.125}html.theme--documenter-dark .title strong{color:inherit;font-weight:inherit}html.theme--documenter-dark .title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}html.theme--documenter-dark .title.is-1{font-size:3rem}html.theme--documenter-dark .title.is-2{font-size:2.5rem}html.theme--documenter-dark .title.is-3{font-size:2rem}html.theme--documenter-dark .title.is-4{font-size:1.5rem}html.theme--documenter-dark .title.is-5{font-size:1.25rem}html.theme--documenter-dark .title.is-6{font-size:1rem}html.theme--documenter-dark .title.is-7{font-size:.75rem}html.theme--documenter-dark .subtitle{color:#8c9b9d;font-size:1.25rem;font-weight:400;line-height:1.25}html.theme--documenter-dark .subtitle strong{color:#8c9b9d;font-weight:600}html.theme--documenter-dark .subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}html.theme--documenter-dark .subtitle.is-1{font-size:3rem}html.theme--documenter-dark .subtitle.is-2{font-size:2.5rem}html.theme--documenter-dark .subtitle.is-3{font-size:2rem}html.theme--documenter-dark .subtitle.is-4{font-size:1.5rem}html.theme--documenter-dark .subtitle.is-5{font-size:1.25rem}html.theme--documenter-dark .subtitle.is-6{font-size:1rem}html.theme--documenter-dark .subtitle.is-7{font-size:.75rem}html.theme--documenter-dark .heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}html.theme--documenter-dark .number{align-items:center;background-color:#282f2f;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#1f2424;border-color:#5e6d6f;border-radius:.4em;color:#dbdee0}html.theme--documenter-dark .select select::-moz-placeholder,html.theme--documenter-dark .textarea::-moz-placeholder,html.theme--documenter-dark .input::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select::-webkit-input-placeholder,html.theme--documenter-dark .textarea::-webkit-input-placeholder,html.theme--documenter-dark .input::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:-moz-placeholder,html.theme--documenter-dark .textarea:-moz-placeholder,html.theme--documenter-dark .input:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select:-ms-input-placeholder,html.theme--documenter-dark .textarea:-ms-input-placeholder,html.theme--documenter-dark .input:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:hover,html.theme--documenter-dark .textarea:hover,html.theme--documenter-dark .input:hover,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:hover,html.theme--documenter-dark .select select.is-hovered,html.theme--documenter-dark .is-hovered.textarea,html.theme--documenter-dark .is-hovered.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#8c9b9d}html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{border-color:#1abc9c;box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#8c9b9d;border-color:#282f2f;box-shadow:none;color:#fff}html.theme--documenter-dark .select select[disabled]::-moz-placeholder,html.theme--documenter-dark .textarea[disabled]::-moz-placeholder,html.theme--documenter-dark .input[disabled]::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .textarea[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .input[disabled]::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-moz-placeholder,html.theme--documenter-dark .textarea[disabled]:-moz-placeholder,html.theme--documenter-dark .input[disabled]:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-ms-input-placeholder,html.theme--documenter-dark .textarea[disabled]:-ms-input-placeholder,html.theme--documenter-dark .input[disabled]:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 0.0625em 0.125em rgba(10,10,10,0.05);max-width:100%;width:100%}html.theme--documenter-dark .textarea[readonly],html.theme--documenter-dark .input[readonly],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}html.theme--documenter-dark .is-white.textarea,html.theme--documenter-dark .is-white.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}html.theme--documenter-dark .is-white.textarea:focus,html.theme--documenter-dark .is-white.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:focus,html.theme--documenter-dark .is-white.is-focused.textarea,html.theme--documenter-dark .is-white.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-white.textarea:active,html.theme--documenter-dark .is-white.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:active,html.theme--documenter-dark .is-white.is-active.textarea,html.theme--documenter-dark .is-white.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .is-black.textarea,html.theme--documenter-dark .is-black.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}html.theme--documenter-dark .is-black.textarea:focus,html.theme--documenter-dark .is-black.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:focus,html.theme--documenter-dark .is-black.is-focused.textarea,html.theme--documenter-dark .is-black.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-black.textarea:active,html.theme--documenter-dark .is-black.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:active,html.theme--documenter-dark .is-black.is-active.textarea,html.theme--documenter-dark .is-black.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .is-light.textarea,html.theme--documenter-dark .is-light.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light{border-color:#ecf0f1}html.theme--documenter-dark .is-light.textarea:focus,html.theme--documenter-dark .is-light.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:focus,html.theme--documenter-dark .is-light.is-focused.textarea,html.theme--documenter-dark .is-light.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-light.textarea:active,html.theme--documenter-dark .is-light.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:active,html.theme--documenter-dark .is-light.is-active.textarea,html.theme--documenter-dark .is-light.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .is-dark.textarea,html.theme--documenter-dark .content kbd.textarea,html.theme--documenter-dark .is-dark.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark,html.theme--documenter-dark .content kbd.input{border-color:#282f2f}html.theme--documenter-dark .is-dark.textarea:focus,html.theme--documenter-dark .content kbd.textarea:focus,html.theme--documenter-dark .is-dark.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:focus,html.theme--documenter-dark .content kbd.input:focus,html.theme--documenter-dark .is-dark.is-focused.textarea,html.theme--documenter-dark .content kbd.is-focused.textarea,html.theme--documenter-dark .is-dark.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .content kbd.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-focused,html.theme--documenter-dark .is-dark.textarea:active,html.theme--documenter-dark .content kbd.textarea:active,html.theme--documenter-dark .is-dark.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:active,html.theme--documenter-dark .content kbd.input:active,html.theme--documenter-dark .is-dark.is-active.textarea,html.theme--documenter-dark .content kbd.is-active.textarea,html.theme--documenter-dark .is-dark.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .content kbd.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .is-primary.textarea,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink{border-color:#375a7f}html.theme--documenter-dark .is-primary.textarea:focus,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:focus,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.is-focused.textarea,html.theme--documenter-dark .docstring>section>a.is-focused.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .docstring>section>a.is-focused.input.docs-sourcelink,html.theme--documenter-dark .is-primary.textarea:active,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:active,html.theme--documenter-dark .is-primary.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:active,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:active,html.theme--documenter-dark .is-primary.is-active.textarea,html.theme--documenter-dark .docstring>section>a.is-active.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .is-link.textarea,html.theme--documenter-dark .is-link.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link{border-color:#1abc9c}html.theme--documenter-dark .is-link.textarea:focus,html.theme--documenter-dark .is-link.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:focus,html.theme--documenter-dark .is-link.is-focused.textarea,html.theme--documenter-dark .is-link.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-link.textarea:active,html.theme--documenter-dark .is-link.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:active,html.theme--documenter-dark .is-link.is-active.textarea,html.theme--documenter-dark .is-link.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .is-info.textarea,html.theme--documenter-dark .is-info.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info{border-color:#024c7d}html.theme--documenter-dark .is-info.textarea:focus,html.theme--documenter-dark .is-info.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:focus,html.theme--documenter-dark .is-info.is-focused.textarea,html.theme--documenter-dark .is-info.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-info.textarea:active,html.theme--documenter-dark .is-info.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:active,html.theme--documenter-dark .is-info.is-active.textarea,html.theme--documenter-dark .is-info.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .is-success.textarea,html.theme--documenter-dark .is-success.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success{border-color:#008438}html.theme--documenter-dark .is-success.textarea:focus,html.theme--documenter-dark .is-success.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:focus,html.theme--documenter-dark .is-success.is-focused.textarea,html.theme--documenter-dark .is-success.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-success.textarea:active,html.theme--documenter-dark .is-success.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:active,html.theme--documenter-dark .is-success.is-active.textarea,html.theme--documenter-dark .is-success.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .is-warning.textarea,html.theme--documenter-dark .is-warning.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ad8100}html.theme--documenter-dark .is-warning.textarea:focus,html.theme--documenter-dark .is-warning.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:focus,html.theme--documenter-dark .is-warning.is-focused.textarea,html.theme--documenter-dark .is-warning.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-warning.textarea:active,html.theme--documenter-dark .is-warning.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:active,html.theme--documenter-dark .is-warning.is-active.textarea,html.theme--documenter-dark .is-warning.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .is-danger.textarea,html.theme--documenter-dark .is-danger.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#9e1b0d}html.theme--documenter-dark .is-danger.textarea:focus,html.theme--documenter-dark .is-danger.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:focus,html.theme--documenter-dark .is-danger.is-focused.textarea,html.theme--documenter-dark .is-danger.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-danger.textarea:active,html.theme--documenter-dark .is-danger.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:active,html.theme--documenter-dark .is-danger.is-active.textarea,html.theme--documenter-dark .is-danger.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .is-small.textarea,html.theme--documenter-dark .is-small.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .is-medium.textarea,html.theme--documenter-dark .is-medium.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}html.theme--documenter-dark .is-large.textarea,html.theme--documenter-dark .is-large.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}html.theme--documenter-dark .is-fullwidth.textarea,html.theme--documenter-dark .is-fullwidth.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}html.theme--documenter-dark .is-inline.textarea,html.theme--documenter-dark .is-inline.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}html.theme--documenter-dark .input.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}html.theme--documenter-dark .input.is-static,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}html.theme--documenter-dark .textarea{display:block;max-width:100%;min-width:100%;padding:calc(0.75em - 1px);resize:vertical}html.theme--documenter-dark .textarea:not([rows]){max-height:40em;min-height:8em}html.theme--documenter-dark .textarea[rows]{height:initial}html.theme--documenter-dark .textarea.has-fixed-size{resize:none}html.theme--documenter-dark .radio,html.theme--documenter-dark .checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}html.theme--documenter-dark .radio input,html.theme--documenter-dark .checkbox input{cursor:pointer}html.theme--documenter-dark .radio:hover,html.theme--documenter-dark .checkbox:hover{color:#8c9b9d}html.theme--documenter-dark .radio[disabled],html.theme--documenter-dark .checkbox[disabled],fieldset[disabled] html.theme--documenter-dark .radio,fieldset[disabled] html.theme--documenter-dark .checkbox,html.theme--documenter-dark .radio input[disabled],html.theme--documenter-dark .checkbox input[disabled]{color:#fff;cursor:not-allowed}html.theme--documenter-dark .radio+.radio{margin-left:.5em}html.theme--documenter-dark .select{display:inline-block;max-width:100%;position:relative;vertical-align:top}html.theme--documenter-dark .select:not(.is-multiple){height:2.5em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border-color:#1abc9c;right:1.125em;z-index:4}html.theme--documenter-dark .select.is-rounded select,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select select{border-radius:9999px;padding-left:1em}html.theme--documenter-dark .select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}html.theme--documenter-dark .select select::-ms-expand{display:none}html.theme--documenter-dark .select select[disabled]:hover,fieldset[disabled] html.theme--documenter-dark .select select:hover{border-color:#282f2f}html.theme--documenter-dark .select select:not([multiple]){padding-right:2.5em}html.theme--documenter-dark .select select[multiple]{height:auto;padding:0}html.theme--documenter-dark .select select[multiple] option{padding:0.5em 1em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading):hover::after{border-color:#8c9b9d}html.theme--documenter-dark .select.is-white:not(:hover)::after{border-color:#fff}html.theme--documenter-dark .select.is-white select{border-color:#fff}html.theme--documenter-dark .select.is-white select:hover,html.theme--documenter-dark .select.is-white select.is-hovered{border-color:#f2f2f2}html.theme--documenter-dark .select.is-white select:focus,html.theme--documenter-dark .select.is-white select.is-focused,html.theme--documenter-dark .select.is-white select:active,html.theme--documenter-dark .select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .select.is-black:not(:hover)::after{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select:hover,html.theme--documenter-dark .select.is-black select.is-hovered{border-color:#000}html.theme--documenter-dark .select.is-black select:focus,html.theme--documenter-dark .select.is-black select.is-focused,html.theme--documenter-dark .select.is-black select:active,html.theme--documenter-dark .select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .select.is-light:not(:hover)::after{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select:hover,html.theme--documenter-dark .select.is-light select.is-hovered{border-color:#dde4e6}html.theme--documenter-dark .select.is-light select:focus,html.theme--documenter-dark .select.is-light select.is-focused,html.theme--documenter-dark .select.is-light select:active,html.theme--documenter-dark .select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .select.is-dark:not(:hover)::after,html.theme--documenter-dark .content kbd.select:not(:hover)::after{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select,html.theme--documenter-dark .content kbd.select select{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select:hover,html.theme--documenter-dark .content kbd.select select:hover,html.theme--documenter-dark .select.is-dark select.is-hovered,html.theme--documenter-dark .content kbd.select select.is-hovered{border-color:#1d2122}html.theme--documenter-dark .select.is-dark select:focus,html.theme--documenter-dark .content kbd.select select:focus,html.theme--documenter-dark .select.is-dark select.is-focused,html.theme--documenter-dark .content kbd.select select.is-focused,html.theme--documenter-dark .select.is-dark select:active,html.theme--documenter-dark .content kbd.select select:active,html.theme--documenter-dark .select.is-dark select.is-active,html.theme--documenter-dark .content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .select.is-primary:not(:hover)::after,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select:hover,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:hover,html.theme--documenter-dark .select.is-primary select.is-hovered,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#2f4d6d}html.theme--documenter-dark .select.is-primary select:focus,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:focus,html.theme--documenter-dark .select.is-primary select.is-focused,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-focused,html.theme--documenter-dark .select.is-primary select:active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:active,html.theme--documenter-dark .select.is-primary select.is-active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .select.is-link:not(:hover)::after{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select:hover,html.theme--documenter-dark .select.is-link select.is-hovered{border-color:#17a689}html.theme--documenter-dark .select.is-link select:focus,html.theme--documenter-dark .select.is-link select.is-focused,html.theme--documenter-dark .select.is-link select:active,html.theme--documenter-dark .select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select.is-info:not(:hover)::after{border-color:#024c7d}html.theme--documenter-dark .select.is-info select{border-color:#024c7d}html.theme--documenter-dark .select.is-info select:hover,html.theme--documenter-dark .select.is-info select.is-hovered{border-color:#023d64}html.theme--documenter-dark .select.is-info select:focus,html.theme--documenter-dark .select.is-info select.is-focused,html.theme--documenter-dark .select.is-info select:active,html.theme--documenter-dark .select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .select.is-success:not(:hover)::after{border-color:#008438}html.theme--documenter-dark .select.is-success select{border-color:#008438}html.theme--documenter-dark .select.is-success select:hover,html.theme--documenter-dark .select.is-success select.is-hovered{border-color:#006b2d}html.theme--documenter-dark .select.is-success select:focus,html.theme--documenter-dark .select.is-success select.is-focused,html.theme--documenter-dark .select.is-success select:active,html.theme--documenter-dark .select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .select.is-warning:not(:hover)::after{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select:hover,html.theme--documenter-dark .select.is-warning select.is-hovered{border-color:#946e00}html.theme--documenter-dark .select.is-warning select:focus,html.theme--documenter-dark .select.is-warning select.is-focused,html.theme--documenter-dark .select.is-warning select:active,html.theme--documenter-dark .select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .select.is-danger:not(:hover)::after{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select:hover,html.theme--documenter-dark .select.is-danger select.is-hovered{border-color:#86170b}html.theme--documenter-dark .select.is-danger select:focus,html.theme--documenter-dark .select.is-danger select.is-focused,html.theme--documenter-dark .select.is-danger select:active,html.theme--documenter-dark .select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .select.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .select.is-medium{font-size:1.25rem}html.theme--documenter-dark .select.is-large{font-size:1.5rem}html.theme--documenter-dark .select.is-disabled::after{border-color:#fff !important;opacity:0.5}html.theme--documenter-dark .select.is-fullwidth{width:100%}html.theme--documenter-dark .select.is-fullwidth select{width:100%}html.theme--documenter-dark .select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:0.625em;transform:none}html.theme--documenter-dark .select.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .select.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .select.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}html.theme--documenter-dark .file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:hover .file-cta,html.theme--documenter-dark .file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:focus .file-cta,html.theme--documenter-dark .file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}html.theme--documenter-dark .file.is-white:active .file-cta,html.theme--documenter-dark .file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:hover .file-cta,html.theme--documenter-dark .file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:focus .file-cta,html.theme--documenter-dark .file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}html.theme--documenter-dark .file.is-black:active .file-cta,html.theme--documenter-dark .file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-light .file-cta{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:hover .file-cta,html.theme--documenter-dark .file.is-light.is-hovered .file-cta{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:focus .file-cta,html.theme--documenter-dark .file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(236,240,241,0.25);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:active .file-cta,html.theme--documenter-dark .file.is-light.is-active .file-cta{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-dark .file-cta,html.theme--documenter-dark .content kbd.file .file-cta{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:hover .file-cta,html.theme--documenter-dark .content kbd.file:hover .file-cta,html.theme--documenter-dark .file.is-dark.is-hovered .file-cta,html.theme--documenter-dark .content kbd.file.is-hovered .file-cta{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:focus .file-cta,html.theme--documenter-dark .content kbd.file:focus .file-cta,html.theme--documenter-dark .file.is-dark.is-focused .file-cta,html.theme--documenter-dark .content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(40,47,47,0.25);color:#fff}html.theme--documenter-dark .file.is-dark:active .file-cta,html.theme--documenter-dark .content kbd.file:active .file-cta,html.theme--documenter-dark .file.is-dark.is-active .file-cta,html.theme--documenter-dark .content kbd.file.is-active .file-cta{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink .file-cta{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:hover .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:hover .file-cta,html.theme--documenter-dark .file.is-primary.is-hovered .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:focus .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:focus .file-cta,html.theme--documenter-dark .file.is-primary.is-focused .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(55,90,127,0.25);color:#fff}html.theme--documenter-dark .file.is-primary:active .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:active .file-cta,html.theme--documenter-dark .file.is-primary.is-active .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link .file-cta{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:hover .file-cta,html.theme--documenter-dark .file.is-link.is-hovered .file-cta{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:focus .file-cta,html.theme--documenter-dark .file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(26,188,156,0.25);color:#fff}html.theme--documenter-dark .file.is-link:active .file-cta,html.theme--documenter-dark .file.is-link.is-active .file-cta{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info .file-cta{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:hover .file-cta,html.theme--documenter-dark .file.is-info.is-hovered .file-cta{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:focus .file-cta,html.theme--documenter-dark .file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(2,76,125,0.25);color:#fff}html.theme--documenter-dark .file.is-info:active .file-cta,html.theme--documenter-dark .file.is-info.is-active .file-cta{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success .file-cta{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:hover .file-cta,html.theme--documenter-dark .file.is-success.is-hovered .file-cta{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:focus .file-cta,html.theme--documenter-dark .file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(0,132,56,0.25);color:#fff}html.theme--documenter-dark .file.is-success:active .file-cta,html.theme--documenter-dark .file.is-success.is-active .file-cta{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning .file-cta{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:hover .file-cta,html.theme--documenter-dark .file.is-warning.is-hovered .file-cta{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:focus .file-cta,html.theme--documenter-dark .file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(173,129,0,0.25);color:#fff}html.theme--documenter-dark .file.is-warning:active .file-cta,html.theme--documenter-dark .file.is-warning.is-active .file-cta{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger .file-cta{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:hover .file-cta,html.theme--documenter-dark .file.is-danger.is-hovered .file-cta{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:focus .file-cta,html.theme--documenter-dark .file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(158,27,13,0.25);color:#fff}html.theme--documenter-dark .file.is-danger:active .file-cta,html.theme--documenter-dark .file.is-danger.is-active .file-cta{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}html.theme--documenter-dark .file.is-normal{font-size:1rem}html.theme--documenter-dark .file.is-medium{font-size:1.25rem}html.theme--documenter-dark .file.is-medium .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-large{font-size:1.5rem}html.theme--documenter-dark .file.is-large .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .file.has-name.is-empty .file-cta{border-radius:.4em}html.theme--documenter-dark .file.has-name.is-empty .file-name{display:none}html.theme--documenter-dark .file.is-boxed .file-label{flex-direction:column}html.theme--documenter-dark .file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}html.theme--documenter-dark .file.is-boxed .file-name{border-width:0 1px 1px}html.theme--documenter-dark .file.is-boxed .file-icon{height:1.5em;width:1.5em}html.theme--documenter-dark .file.is-boxed .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-boxed.is-small .file-icon .fa,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}html.theme--documenter-dark .file.is-boxed.is-medium .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.is-boxed.is-large .file-icon .fa{font-size:35px}html.theme--documenter-dark .file.is-boxed.has-name .file-cta{border-radius:.4em .4em 0 0}html.theme--documenter-dark .file.is-boxed.has-name .file-name{border-radius:0 0 .4em .4em;border-width:0 1px 1px}html.theme--documenter-dark .file.is-centered{justify-content:center}html.theme--documenter-dark .file.is-fullwidth .file-label{width:100%}html.theme--documenter-dark .file.is-fullwidth .file-name{flex-grow:1;max-width:none}html.theme--documenter-dark .file.is-right{justify-content:flex-end}html.theme--documenter-dark .file.is-right .file-cta{border-radius:0 .4em .4em 0}html.theme--documenter-dark .file.is-right .file-name{border-radius:.4em 0 0 .4em;border-width:1px 0 1px 1px;order:-1}html.theme--documenter-dark .file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}html.theme--documenter-dark .file-label:hover .file-cta{background-color:#232829;color:#f2f2f2}html.theme--documenter-dark .file-label:hover .file-name{border-color:#596668}html.theme--documenter-dark .file-label:active .file-cta{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .file-label:active .file-name{border-color:#535f61}html.theme--documenter-dark .file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-radius:.4em;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}html.theme--documenter-dark .file-cta{background-color:#282f2f;color:#fff}html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}html.theme--documenter-dark .file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}html.theme--documenter-dark .file-icon .fa{font-size:14px}html.theme--documenter-dark .label{color:#f2f2f2;display:block;font-size:1rem;font-weight:700}html.theme--documenter-dark .label:not(:last-child){margin-bottom:0.5em}html.theme--documenter-dark .label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}html.theme--documenter-dark .label.is-medium{font-size:1.25rem}html.theme--documenter-dark .label.is-large{font-size:1.5rem}html.theme--documenter-dark .help{display:block;font-size:.75rem;margin-top:0.25rem}html.theme--documenter-dark .help.is-white{color:#fff}html.theme--documenter-dark .help.is-black{color:#0a0a0a}html.theme--documenter-dark .help.is-light{color:#ecf0f1}html.theme--documenter-dark .help.is-dark,html.theme--documenter-dark .content kbd.help{color:#282f2f}html.theme--documenter-dark .help.is-primary,html.theme--documenter-dark .docstring>section>a.help.docs-sourcelink{color:#375a7f}html.theme--documenter-dark .help.is-link{color:#1abc9c}html.theme--documenter-dark .help.is-info{color:#024c7d}html.theme--documenter-dark .help.is-success{color:#008438}html.theme--documenter-dark .help.is-warning{color:#ad8100}html.theme--documenter-dark .help.is-danger{color:#9e1b0d}html.theme--documenter-dark .field:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.has-addons{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.has-addons .control:not(:last-child){margin-right:-1px}html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .button,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]){z-index:3}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}html.theme--documenter-dark .field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.has-addons.has-addons-centered{justify-content:center}html.theme--documenter-dark .field.has-addons.has-addons-right{justify-content:flex-end}html.theme--documenter-dark .field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .field.is-grouped{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.is-grouped>.control{flex-shrink:0}html.theme--documenter-dark .field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.is-grouped.is-grouped-centered{justify-content:center}html.theme--documenter-dark .field.is-grouped.is-grouped-right{justify-content:flex-end}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline{flex-wrap:wrap}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:last-child,html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field.is-horizontal{display:flex}}html.theme--documenter-dark .field-label .label{font-size:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}html.theme--documenter-dark .field-label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-normal{padding-top:0.375em}html.theme--documenter-dark .field-label.is-medium{font-size:1.25rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-large{font-size:1.5rem;padding-top:0.375em}}html.theme--documenter-dark .field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}html.theme--documenter-dark .field-body .field{margin-bottom:0}html.theme--documenter-dark .field-body>.field{flex-shrink:1}html.theme--documenter-dark .field-body>.field:not(.is-narrow){flex-grow:1}html.theme--documenter-dark .field-body>.field:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}html.theme--documenter-dark .control.has-icons-left .input:focus~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-left .select:focus~.icon,html.theme--documenter-dark .control.has-icons-right .input:focus~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-right .select:focus~.icon{color:#282f2f}html.theme--documenter-dark .control.has-icons-left .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-small~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-small~.icon{font-size:.75rem}html.theme--documenter-dark .control.has-icons-left .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}html.theme--documenter-dark .control.has-icons-left .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-large~.icon{font-size:1.5rem}html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon{color:#5e6d6f;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}html.theme--documenter-dark .control.has-icons-left .input,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input,html.theme--documenter-dark .control.has-icons-left .select select{padding-left:2.5em}html.theme--documenter-dark .control.has-icons-left .icon.is-left{left:0}html.theme--documenter-dark .control.has-icons-right .input,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input,html.theme--documenter-dark .control.has-icons-right .select select{padding-right:2.5em}html.theme--documenter-dark .control.has-icons-right .icon.is-right{right:0}html.theme--documenter-dark .control.is-loading::after{position:absolute !important;right:.625em;top:0.625em;z-index:4}html.theme--documenter-dark .control.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .control.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .control.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .breadcrumb{font-size:1rem;white-space:nowrap}html.theme--documenter-dark .breadcrumb a{align-items:center;color:#1abc9c;display:flex;justify-content:center;padding:0 .75em}html.theme--documenter-dark .breadcrumb a:hover{color:#1dd2af}html.theme--documenter-dark .breadcrumb li{align-items:center;display:flex}html.theme--documenter-dark .breadcrumb li:first-child a{padding-left:0}html.theme--documenter-dark .breadcrumb li.is-active a{color:#f2f2f2;cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb li+li::before{color:#8c9b9d;content:"\0002f"}html.theme--documenter-dark .breadcrumb ul,html.theme--documenter-dark .breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .breadcrumb .icon:first-child{margin-right:.5em}html.theme--documenter-dark .breadcrumb .icon:last-child{margin-left:.5em}html.theme--documenter-dark .breadcrumb.is-centered ol,html.theme--documenter-dark .breadcrumb.is-centered ul{justify-content:center}html.theme--documenter-dark .breadcrumb.is-right ol,html.theme--documenter-dark .breadcrumb.is-right ul{justify-content:flex-end}html.theme--documenter-dark .breadcrumb.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}html.theme--documenter-dark .breadcrumb.is-medium{font-size:1.25rem}html.theme--documenter-dark .breadcrumb.is-large{font-size:1.5rem}html.theme--documenter-dark .breadcrumb.has-arrow-separator li+li::before{content:"\02192"}html.theme--documenter-dark .breadcrumb.has-bullet-separator li+li::before{content:"\02022"}html.theme--documenter-dark .breadcrumb.has-dot-separator li+li::before{content:"\000b7"}html.theme--documenter-dark .breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}html.theme--documenter-dark .card{background-color:#fff;border-radius:.25rem;box-shadow:#171717;color:#fff;max-width:100%;position:relative}html.theme--documenter-dark .card-footer:first-child,html.theme--documenter-dark .card-content:first-child,html.theme--documenter-dark .card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-footer:last-child,html.theme--documenter-dark .card-content:last-child,html.theme--documenter-dark .card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);display:flex}html.theme--documenter-dark .card-header-title{align-items:center;color:#f2f2f2;display:flex;flex-grow:1;font-weight:700;padding:0.75rem 1rem}html.theme--documenter-dark .card-header-title.is-centered{justify-content:center}html.theme--documenter-dark .card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}html.theme--documenter-dark .card-image{display:block;position:relative}html.theme--documenter-dark .card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-content{background-color:rgba(0,0,0,0);padding:1.5rem}html.theme--documenter-dark .card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #ededed;align-items:stretch;display:flex}html.theme--documenter-dark .card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}html.theme--documenter-dark .card-footer-item:not(:last-child){border-right:1px solid #ededed}html.theme--documenter-dark .card .media:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .dropdown{display:inline-flex;position:relative;vertical-align:top}html.theme--documenter-dark .dropdown.is-active .dropdown-menu,html.theme--documenter-dark .dropdown.is-hoverable:hover .dropdown-menu{display:block}html.theme--documenter-dark .dropdown.is-right .dropdown-menu{left:auto;right:0}html.theme--documenter-dark .dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}html.theme--documenter-dark .dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .dropdown-content{background-color:#282f2f;border-radius:.4em;box-shadow:#171717;padding-bottom:.5rem;padding-top:.5rem}html.theme--documenter-dark .dropdown-item{color:#fff;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}html.theme--documenter-dark a.dropdown-item,html.theme--documenter-dark button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}html.theme--documenter-dark a.dropdown-item:hover,html.theme--documenter-dark button.dropdown-item:hover{background-color:#282f2f;color:#0a0a0a}html.theme--documenter-dark a.dropdown-item.is-active,html.theme--documenter-dark button.dropdown-item.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:0.5rem 0}html.theme--documenter-dark .level{align-items:center;justify-content:space-between}html.theme--documenter-dark .level code{border-radius:.4em}html.theme--documenter-dark .level img{display:inline-block;vertical-align:top}html.theme--documenter-dark .level.is-mobile{display:flex}html.theme--documenter-dark .level.is-mobile .level-left,html.theme--documenter-dark .level.is-mobile .level-right{display:flex}html.theme--documenter-dark .level.is-mobile .level-left+.level-right{margin-top:0}html.theme--documenter-dark .level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level{display:flex}html.theme--documenter-dark .level>.level-item:not(.is-narrow){flex-grow:1}}html.theme--documenter-dark .level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}html.theme--documenter-dark .level-item .title,html.theme--documenter-dark .level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){html.theme--documenter-dark .level-item:not(:last-child){margin-bottom:.75rem}}html.theme--documenter-dark .level-left,html.theme--documenter-dark .level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .level-left .level-item.is-flexible,html.theme--documenter-dark .level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left .level-item:not(:last-child),html.theme--documenter-dark .level-right .level-item:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){html.theme--documenter-dark .level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left{display:flex}}html.theme--documenter-dark .level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-right{display:flex}}html.theme--documenter-dark .media{align-items:flex-start;display:flex;text-align:inherit}html.theme--documenter-dark .media .content:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .media .media{border-top:1px solid rgba(94,109,111,0.5);display:flex;padding-top:.75rem}html.theme--documenter-dark .media .media .content:not(:last-child),html.theme--documenter-dark .media .media .control:not(:last-child){margin-bottom:.5rem}html.theme--documenter-dark .media .media .media{padding-top:.5rem}html.theme--documenter-dark .media .media .media+.media{margin-top:.5rem}html.theme--documenter-dark .media+.media{border-top:1px solid rgba(94,109,111,0.5);margin-top:1rem;padding-top:1rem}html.theme--documenter-dark .media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}html.theme--documenter-dark .media-left,html.theme--documenter-dark .media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .media-left{margin-right:1rem}html.theme--documenter-dark .media-right{margin-left:1rem}html.theme--documenter-dark .media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .media-content{overflow-x:auto}}html.theme--documenter-dark .menu{font-size:1rem}html.theme--documenter-dark .menu.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}html.theme--documenter-dark .menu.is-medium{font-size:1.25rem}html.theme--documenter-dark .menu.is-large{font-size:1.5rem}html.theme--documenter-dark .menu-list{line-height:1.25}html.theme--documenter-dark .menu-list a{border-radius:3px;color:#fff;display:block;padding:0.5em 0.75em}html.theme--documenter-dark .menu-list a:hover{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .menu-list a.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .menu-list li ul{border-left:1px solid #5e6d6f;margin:.75em;padding-left:.75em}html.theme--documenter-dark .menu-label{color:#fff;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}html.theme--documenter-dark .menu-label:not(:first-child){margin-top:1em}html.theme--documenter-dark .menu-label:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .message{background-color:#282f2f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .message strong{color:currentColor}html.theme--documenter-dark .message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .message.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}html.theme--documenter-dark .message.is-medium{font-size:1.25rem}html.theme--documenter-dark .message.is-large{font-size:1.5rem}html.theme--documenter-dark .message.is-white{background-color:#fff}html.theme--documenter-dark .message.is-white .message-header{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .message.is-white .message-body{border-color:#fff}html.theme--documenter-dark .message.is-black{background-color:#fafafa}html.theme--documenter-dark .message.is-black .message-header{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .message.is-black .message-body{border-color:#0a0a0a}html.theme--documenter-dark .message.is-light{background-color:#f9fafb}html.theme--documenter-dark .message.is-light .message-header{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .message.is-light .message-body{border-color:#ecf0f1}html.theme--documenter-dark .message.is-dark,html.theme--documenter-dark .content kbd.message{background-color:#f9fafa}html.theme--documenter-dark .message.is-dark .message-header,html.theme--documenter-dark .content kbd.message .message-header{background-color:#282f2f;color:#fff}html.theme--documenter-dark .message.is-dark .message-body,html.theme--documenter-dark .content kbd.message .message-body{border-color:#282f2f}html.theme--documenter-dark .message.is-primary,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink{background-color:#f1f5f9}html.theme--documenter-dark .message.is-primary .message-header,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-header{background-color:#375a7f;color:#fff}html.theme--documenter-dark .message.is-primary .message-body,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-body{border-color:#375a7f;color:#4d7eb2}html.theme--documenter-dark .message.is-link{background-color:#edfdf9}html.theme--documenter-dark .message.is-link .message-header{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .message.is-link .message-body{border-color:#1abc9c;color:#15987e}html.theme--documenter-dark .message.is-info{background-color:#ebf7ff}html.theme--documenter-dark .message.is-info .message-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .message.is-info .message-body{border-color:#024c7d;color:#0e9dfb}html.theme--documenter-dark .message.is-success{background-color:#ebfff3}html.theme--documenter-dark .message.is-success .message-header{background-color:#008438;color:#fff}html.theme--documenter-dark .message.is-success .message-body{border-color:#008438;color:#00eb64}html.theme--documenter-dark .message.is-warning{background-color:#fffaeb}html.theme--documenter-dark .message.is-warning .message-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .message.is-warning .message-body{border-color:#ad8100;color:#d19c00}html.theme--documenter-dark .message.is-danger{background-color:#fdeeec}html.theme--documenter-dark .message.is-danger .message-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .message.is-danger .message-body{border-color:#9e1b0d;color:#ec311d}html.theme--documenter-dark .message-header{align-items:center;background-color:#fff;border-radius:.4em .4em 0 0;color:rgba(0,0,0,0.7);display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}html.theme--documenter-dark .message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}html.theme--documenter-dark .message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}html.theme--documenter-dark .message-body{border-color:#5e6d6f;border-radius:.4em;border-style:solid;border-width:0 0 0 4px;color:#fff;padding:1.25em 1.5em}html.theme--documenter-dark .message-body code,html.theme--documenter-dark .message-body pre{background-color:#fff}html.theme--documenter-dark .message-body pre code{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}html.theme--documenter-dark .modal.is-active{display:flex}html.theme--documenter-dark .modal-background{background-color:rgba(10,10,10,0.86)}html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px){html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}html.theme--documenter-dark .modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}html.theme--documenter-dark .modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}html.theme--documenter-dark .modal-card-head,html.theme--documenter-dark .modal-card-foot{align-items:center;background-color:#282f2f;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}html.theme--documenter-dark .modal-card-head{border-bottom:1px solid #5e6d6f;border-top-left-radius:8px;border-top-right-radius:8px}html.theme--documenter-dark .modal-card-title{color:#f2f2f2;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}html.theme--documenter-dark .modal-card-foot{border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid #5e6d6f}html.theme--documenter-dark .modal-card-foot .button:not(:last-child){margin-right:.5em}html.theme--documenter-dark .modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}html.theme--documenter-dark .navbar{background-color:#375a7f;min-height:4rem;position:relative;z-index:30}html.theme--documenter-dark .navbar.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-white .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}html.theme--documenter-dark .navbar.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-black .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}html.theme--documenter-dark .navbar.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-light .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}}html.theme--documenter-dark .navbar.is-dark,html.theme--documenter-dark .content kbd.navbar{background-color:#282f2f;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-burger,html.theme--documenter-dark .content kbd.navbar .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-dark .navbar-start>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-end>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#282f2f;color:#fff}}html.theme--documenter-dark .navbar.is-primary,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-burger,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-primary .navbar-start>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-end>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#375a7f;color:#fff}}html.theme--documenter-dark .navbar.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-link .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c;color:#fff}}html.theme--documenter-dark .navbar.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-info .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#024c7d;color:#fff}}html.theme--documenter-dark .navbar.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-success .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#008438;color:#fff}}html.theme--documenter-dark .navbar.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-warning .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ad8100;color:#fff}}html.theme--documenter-dark .navbar.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-danger .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#9e1b0d;color:#fff}}html.theme--documenter-dark .navbar>.container{align-items:stretch;display:flex;min-height:4rem;width:100%}html.theme--documenter-dark .navbar.has-shadow{box-shadow:0 2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-bottom,html.theme--documenter-dark .navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-top{top:0}html.theme--documenter-dark html.has-navbar-fixed-top,html.theme--documenter-dark body.has-navbar-fixed-top{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom,html.theme--documenter-dark body.has-navbar-fixed-bottom{padding-bottom:4rem}html.theme--documenter-dark .navbar-brand,html.theme--documenter-dark .navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:4rem}html.theme--documenter-dark .navbar-brand a.navbar-item:focus,html.theme--documenter-dark .navbar-brand a.navbar-item:hover{background-color:transparent}html.theme--documenter-dark .navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}html.theme--documenter-dark .navbar-burger{color:#fff;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;cursor:pointer;display:block;height:4rem;position:relative;width:4rem;margin-left:auto}html.theme--documenter-dark .navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}html.theme--documenter-dark .navbar-burger span:nth-child(1){top:calc(50% - 6px)}html.theme--documenter-dark .navbar-burger span:nth-child(2){top:calc(50% - 1px)}html.theme--documenter-dark .navbar-burger span:nth-child(3){top:calc(50% + 4px)}html.theme--documenter-dark .navbar-burger:hover{background-color:rgba(0,0,0,0.05)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(2){opacity:0}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}html.theme--documenter-dark .navbar-menu{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{color:#fff;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}html.theme--documenter-dark .navbar-item .icon:only-child,html.theme--documenter-dark .navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}html.theme--documenter-dark a.navbar-item,html.theme--documenter-dark .navbar-link{cursor:pointer}html.theme--documenter-dark a.navbar-item:focus,html.theme--documenter-dark a.navbar-item:focus-within,html.theme--documenter-dark a.navbar-item:hover,html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link:focus,html.theme--documenter-dark .navbar-link:focus-within,html.theme--documenter-dark .navbar-link:hover,html.theme--documenter-dark .navbar-link.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-item{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .navbar-item img{max-height:1.75rem}html.theme--documenter-dark .navbar-item.has-dropdown{padding:0}html.theme--documenter-dark .navbar-item.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-item.is-tab{border-bottom:1px solid transparent;min-height:4rem;padding-bottom:calc(0.5rem - 1px)}html.theme--documenter-dark .navbar-item.is-tab:focus,html.theme--documenter-dark .navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c}html.theme--documenter-dark .navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c;border-bottom-style:solid;border-bottom-width:3px;color:#1abc9c;padding-bottom:calc(0.5rem - 3px)}html.theme--documenter-dark .navbar-content{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-link:not(.is-arrowless){padding-right:2.5em}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after{border-color:#fff;margin-top:-0.375em;right:1.125em}html.theme--documenter-dark .navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}html.theme--documenter-dark .navbar-divider{background-color:rgba(0,0,0,0.2);border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar>.container{display:block}html.theme--documenter-dark .navbar-brand .navbar-item,html.theme--documenter-dark .navbar-tabs .navbar-item{align-items:center;display:flex}html.theme--documenter-dark .navbar-link::after{display:none}html.theme--documenter-dark .navbar-menu{background-color:#375a7f;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}html.theme--documenter-dark .navbar-menu.is-active{display:block}html.theme--documenter-dark .navbar.is-fixed-bottom-touch,html.theme--documenter-dark .navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-touch{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-touch{top:0}html.theme--documenter-dark .navbar.is-fixed-top .navbar-menu,html.theme--documenter-dark .navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 4rem);overflow:auto}html.theme--documenter-dark html.has-navbar-fixed-top-touch,html.theme--documenter-dark body.has-navbar-fixed-top-touch{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-touch,html.theme--documenter-dark body.has-navbar-fixed-bottom-touch{padding-bottom:4rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar,html.theme--documenter-dark .navbar-menu,html.theme--documenter-dark .navbar-start,html.theme--documenter-dark .navbar-end{align-items:stretch;display:flex}html.theme--documenter-dark .navbar{min-height:4rem}html.theme--documenter-dark .navbar.is-spaced{padding:1rem 2rem}html.theme--documenter-dark .navbar.is-spaced .navbar-start,html.theme--documenter-dark .navbar.is-spaced .navbar-end{align-items:center}html.theme--documenter-dark .navbar.is-spaced a.navbar-item,html.theme--documenter-dark .navbar.is-spaced .navbar-link{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent a.navbar-item:hover,html.theme--documenter-dark .navbar.is-transparent a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-transparent .navbar-link:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-link:hover,html.theme--documenter-dark .navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-burger{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{align-items:center;display:flex}html.theme--documenter-dark .navbar-item.has-dropdown{align-items:stretch}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:1px solid rgba(0,0,0,0.2);border-radius:8px 8px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}html.theme--documenter-dark .navbar-menu{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .navbar-start{justify-content:flex-start;margin-right:auto}html.theme--documenter-dark .navbar-end{justify-content:flex-end;margin-left:auto}html.theme--documenter-dark .navbar-dropdown{background-color:#375a7f;border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid rgba(0,0,0,0.2);box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}html.theme--documenter-dark .navbar-dropdown a.navbar-item{padding-right:3rem}html.theme--documenter-dark .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}.navbar.is-spaced html.theme--documenter-dark .navbar-dropdown,html.theme--documenter-dark .navbar-dropdown.is-boxed{border-radius:8px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}html.theme--documenter-dark .navbar-dropdown.is-right{left:auto;right:0}html.theme--documenter-dark .navbar-divider{display:block}html.theme--documenter-dark .navbar>.container .navbar-brand,html.theme--documenter-dark .container>.navbar .navbar-brand{margin-left:-.75rem}html.theme--documenter-dark .navbar>.container .navbar-menu,html.theme--documenter-dark .container>.navbar .navbar-menu{margin-right:-.75rem}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop,html.theme--documenter-dark .navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-desktop{top:0}html.theme--documenter-dark html.has-navbar-fixed-top-desktop,html.theme--documenter-dark body.has-navbar-fixed-top-desktop{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-desktop,html.theme--documenter-dark body.has-navbar-fixed-bottom-desktop{padding-bottom:4rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-top,html.theme--documenter-dark body.has-spaced-navbar-fixed-top{padding-top:6rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-bottom,html.theme--documenter-dark body.has-spaced-navbar-fixed-bottom{padding-bottom:6rem}html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link.is-active{color:#1abc9c}html.theme--documenter-dark a.navbar-item.is-active:not(:focus):not(:hover),html.theme--documenter-dark .navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}html.theme--documenter-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown.is-active .navbar-link{background-color:rgba(0,0,0,0)}}html.theme--documenter-dark .hero.is-fullheight-with-navbar{min-height:calc(100vh - 4rem)}html.theme--documenter-dark .pagination{font-size:1rem;margin:-.25rem}html.theme--documenter-dark .pagination.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}html.theme--documenter-dark .pagination.is-medium{font-size:1.25rem}html.theme--documenter-dark .pagination.is-large{font-size:1.5rem}html.theme--documenter-dark .pagination.is-rounded .pagination-previous,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,html.theme--documenter-dark .pagination.is-rounded .pagination-next,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:9999px}html.theme--documenter-dark .pagination.is-rounded .pagination-link,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}html.theme--documenter-dark .pagination,html.theme--documenter-dark .pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link{border-color:#5e6d6f;color:#1abc9c;min-width:2.5em}html.theme--documenter-dark .pagination-previous:hover,html.theme--documenter-dark .pagination-next:hover,html.theme--documenter-dark .pagination-link:hover{border-color:#8c9b9d;color:#1dd2af}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus{border-color:#8c9b9d}html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-previous.is-disabled,html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-next.is-disabled,html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-link.is-disabled{background-color:#5e6d6f;border-color:#5e6d6f;box-shadow:none;color:#fff;opacity:0.5}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{padding-left:.75em;padding-right:.75em;white-space:nowrap}html.theme--documenter-dark .pagination-link.is-current{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .pagination-ellipsis{color:#8c9b9d;pointer-events:none}html.theme--documenter-dark .pagination-list{flex-wrap:wrap}html.theme--documenter-dark .pagination-list li{list-style:none}@media screen and (max-width: 768px){html.theme--documenter-dark .pagination{flex-wrap:wrap}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination-previous{order:2}html.theme--documenter-dark .pagination-next{order:3}html.theme--documenter-dark .pagination{justify-content:space-between;margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination.is-centered .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-centered .pagination-list{justify-content:center;order:2}html.theme--documenter-dark .pagination.is-centered .pagination-next{order:3}html.theme--documenter-dark .pagination.is-right .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-right .pagination-next{order:2}html.theme--documenter-dark .pagination.is-right .pagination-list{justify-content:flex-end;order:3}}html.theme--documenter-dark .panel{border-radius:8px;box-shadow:#171717;font-size:1rem}html.theme--documenter-dark .panel:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}html.theme--documenter-dark .panel.is-white .panel-block.is-active .panel-icon{color:#fff}html.theme--documenter-dark .panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}html.theme--documenter-dark .panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}html.theme--documenter-dark .panel.is-light .panel-heading{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .panel.is-light .panel-tabs a.is-active{border-bottom-color:#ecf0f1}html.theme--documenter-dark .panel.is-light .panel-block.is-active .panel-icon{color:#ecf0f1}html.theme--documenter-dark .panel.is-dark .panel-heading,html.theme--documenter-dark .content kbd.panel .panel-heading{background-color:#282f2f;color:#fff}html.theme--documenter-dark .panel.is-dark .panel-tabs a.is-active,html.theme--documenter-dark .content kbd.panel .panel-tabs a.is-active{border-bottom-color:#282f2f}html.theme--documenter-dark .panel.is-dark .panel-block.is-active .panel-icon,html.theme--documenter-dark .content kbd.panel .panel-block.is-active .panel-icon{color:#282f2f}html.theme--documenter-dark .panel.is-primary .panel-heading,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#375a7f;color:#fff}html.theme--documenter-dark .panel.is-primary .panel-tabs a.is-active,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#375a7f}html.theme--documenter-dark .panel.is-primary .panel-block.is-active .panel-icon,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#375a7f}html.theme--documenter-dark .panel.is-link .panel-heading{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .panel.is-link .panel-tabs a.is-active{border-bottom-color:#1abc9c}html.theme--documenter-dark .panel.is-link .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel.is-info .panel-heading{background-color:#024c7d;color:#fff}html.theme--documenter-dark .panel.is-info .panel-tabs a.is-active{border-bottom-color:#024c7d}html.theme--documenter-dark .panel.is-info .panel-block.is-active .panel-icon{color:#024c7d}html.theme--documenter-dark .panel.is-success .panel-heading{background-color:#008438;color:#fff}html.theme--documenter-dark .panel.is-success .panel-tabs a.is-active{border-bottom-color:#008438}html.theme--documenter-dark .panel.is-success .panel-block.is-active .panel-icon{color:#008438}html.theme--documenter-dark .panel.is-warning .panel-heading{background-color:#ad8100;color:#fff}html.theme--documenter-dark .panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ad8100}html.theme--documenter-dark .panel.is-warning .panel-block.is-active .panel-icon{color:#ad8100}html.theme--documenter-dark .panel.is-danger .panel-heading{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .panel.is-danger .panel-tabs a.is-active{border-bottom-color:#9e1b0d}html.theme--documenter-dark .panel.is-danger .panel-block.is-active .panel-icon{color:#9e1b0d}html.theme--documenter-dark .panel-tabs:not(:last-child),html.theme--documenter-dark .panel-block:not(:last-child){border-bottom:1px solid #ededed}html.theme--documenter-dark .panel-heading{background-color:#343c3d;border-radius:8px 8px 0 0;color:#f2f2f2;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}html.theme--documenter-dark .panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}html.theme--documenter-dark .panel-tabs a{border-bottom:1px solid #5e6d6f;margin-bottom:-1px;padding:0.5em}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#343c3d;color:#17a689}html.theme--documenter-dark .panel-list a{color:#fff}html.theme--documenter-dark .panel-list a:hover{color:#1abc9c}html.theme--documenter-dark .panel-block{align-items:center;color:#f2f2f2;display:flex;justify-content:flex-start;padding:0.5em 0.75em}html.theme--documenter-dark .panel-block input[type="checkbox"]{margin-right:.75em}html.theme--documenter-dark .panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}html.theme--documenter-dark .panel-block.is-wrapped{flex-wrap:wrap}html.theme--documenter-dark .panel-block.is-active{border-left-color:#1abc9c;color:#17a689}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel-block:last-child{border-bottom-left-radius:8px;border-bottom-right-radius:8px}html.theme--documenter-dark a.panel-block,html.theme--documenter-dark label.panel-block{cursor:pointer}html.theme--documenter-dark a.panel-block:hover,html.theme--documenter-dark label.panel-block:hover{background-color:#282f2f}html.theme--documenter-dark .panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#fff;margin-right:.75em}html.theme--documenter-dark .panel-icon .fa{font-size:inherit;line-height:inherit}html.theme--documenter-dark .tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}html.theme--documenter-dark .tabs a{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;color:#fff;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}html.theme--documenter-dark .tabs a:hover{border-bottom-color:#f2f2f2;color:#f2f2f2}html.theme--documenter-dark .tabs li{display:block}html.theme--documenter-dark .tabs li.is-active a{border-bottom-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .tabs ul{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}html.theme--documenter-dark .tabs ul.is-left{padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}html.theme--documenter-dark .tabs .icon:first-child{margin-right:.5em}html.theme--documenter-dark .tabs .icon:last-child{margin-left:.5em}html.theme--documenter-dark .tabs.is-centered ul{justify-content:center}html.theme--documenter-dark .tabs.is-right ul{justify-content:flex-end}html.theme--documenter-dark .tabs.is-boxed a{border:1px solid transparent;border-radius:.4em .4em 0 0}html.theme--documenter-dark .tabs.is-boxed a:hover{background-color:#282f2f;border-bottom-color:#5e6d6f}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#fff;border-color:#5e6d6f;border-bottom-color:rgba(0,0,0,0) !important}html.theme--documenter-dark .tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .tabs.is-toggle a{border-color:#5e6d6f;border-style:solid;border-width:1px;margin-bottom:0;position:relative}html.theme--documenter-dark .tabs.is-toggle a:hover{background-color:#282f2f;border-color:#8c9b9d;z-index:2}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .tabs.is-toggle li:first-child a{border-top-left-radius:.4em;border-bottom-left-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li:last-child a{border-top-right-radius:.4em;border-bottom-right-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li.is-active a{background-color:#1abc9c;border-color:#1abc9c;color:#fff;z-index:1}html.theme--documenter-dark .tabs.is-toggle ul{border-bottom:none}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}html.theme--documenter-dark .tabs.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}html.theme--documenter-dark .tabs.is-medium{font-size:1.25rem}html.theme--documenter-dark .tabs.is-large{font-size:1.5rem}html.theme--documenter-dark .column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>html.theme--documenter-dark .column.is-narrow{flex:none;width:unset}.columns.is-mobile>html.theme--documenter-dark .column.is-full{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-half{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-half{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-0{flex:none;width:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-0{margin-left:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-1{flex:none;width:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-2{margin-left:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-3{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-3{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-4{flex:none;width:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-5{margin-left:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-6{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-6{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-7{flex:none;width:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-8{margin-left:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-9{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-9{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-10{flex:none;width:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-11{margin-left:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-12{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){html.theme--documenter-dark .column.is-narrow-mobile{flex:none;width:unset}html.theme--documenter-dark .column.is-full-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-mobile{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-mobile{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-mobile{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-mobile{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-mobile{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-mobile{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-mobile{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-mobile{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-mobile{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-mobile{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-mobile{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-mobile{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-mobile{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-mobile{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-mobile{margin-left:80%}html.theme--documenter-dark .column.is-0-mobile{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-mobile{margin-left:0%}html.theme--documenter-dark .column.is-1-mobile{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-mobile{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-mobile{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-mobile{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-mobile{margin-left:25%}html.theme--documenter-dark .column.is-4-mobile{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-mobile{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-mobile{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-mobile{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-mobile{margin-left:50%}html.theme--documenter-dark .column.is-7-mobile{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-mobile{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-mobile{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-mobile{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-mobile{margin-left:75%}html.theme--documenter-dark .column.is-10-mobile{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-mobile{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-mobile{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-mobile{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .column.is-narrow,html.theme--documenter-dark .column.is-narrow-tablet{flex:none;width:unset}html.theme--documenter-dark .column.is-full,html.theme--documenter-dark .column.is-full-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters,html.theme--documenter-dark .column.is-three-quarters-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds,html.theme--documenter-dark .column.is-two-thirds-tablet{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half,html.theme--documenter-dark .column.is-half-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third,html.theme--documenter-dark .column.is-one-third-tablet{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter,html.theme--documenter-dark .column.is-one-quarter-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth,html.theme--documenter-dark .column.is-one-fifth-tablet{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths,html.theme--documenter-dark .column.is-two-fifths-tablet{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths,html.theme--documenter-dark .column.is-three-fifths-tablet{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths,html.theme--documenter-dark .column.is-four-fifths-tablet{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters,html.theme--documenter-dark .column.is-offset-three-quarters-tablet{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds,html.theme--documenter-dark .column.is-offset-two-thirds-tablet{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half,html.theme--documenter-dark .column.is-offset-half-tablet{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third,html.theme--documenter-dark .column.is-offset-one-third-tablet{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter,html.theme--documenter-dark .column.is-offset-one-quarter-tablet{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth,html.theme--documenter-dark .column.is-offset-one-fifth-tablet{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths,html.theme--documenter-dark .column.is-offset-two-fifths-tablet{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths,html.theme--documenter-dark .column.is-offset-three-fifths-tablet{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths,html.theme--documenter-dark .column.is-offset-four-fifths-tablet{margin-left:80%}html.theme--documenter-dark .column.is-0,html.theme--documenter-dark .column.is-0-tablet{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0,html.theme--documenter-dark .column.is-offset-0-tablet{margin-left:0%}html.theme--documenter-dark .column.is-1,html.theme--documenter-dark .column.is-1-tablet{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1,html.theme--documenter-dark .column.is-offset-1-tablet{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2,html.theme--documenter-dark .column.is-2-tablet{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2,html.theme--documenter-dark .column.is-offset-2-tablet{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3,html.theme--documenter-dark .column.is-3-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3,html.theme--documenter-dark .column.is-offset-3-tablet{margin-left:25%}html.theme--documenter-dark .column.is-4,html.theme--documenter-dark .column.is-4-tablet{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4,html.theme--documenter-dark .column.is-offset-4-tablet{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5,html.theme--documenter-dark .column.is-5-tablet{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5,html.theme--documenter-dark .column.is-offset-5-tablet{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6,html.theme--documenter-dark .column.is-6-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6,html.theme--documenter-dark .column.is-offset-6-tablet{margin-left:50%}html.theme--documenter-dark .column.is-7,html.theme--documenter-dark .column.is-7-tablet{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7,html.theme--documenter-dark .column.is-offset-7-tablet{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8,html.theme--documenter-dark .column.is-8-tablet{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8,html.theme--documenter-dark .column.is-offset-8-tablet{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9,html.theme--documenter-dark .column.is-9-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9,html.theme--documenter-dark .column.is-offset-9-tablet{margin-left:75%}html.theme--documenter-dark .column.is-10,html.theme--documenter-dark .column.is-10-tablet{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10,html.theme--documenter-dark .column.is-offset-10-tablet{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11,html.theme--documenter-dark .column.is-11-tablet{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11,html.theme--documenter-dark .column.is-offset-11-tablet{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12,html.theme--documenter-dark .column.is-12-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12,html.theme--documenter-dark .column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){html.theme--documenter-dark .column.is-narrow-touch{flex:none;width:unset}html.theme--documenter-dark .column.is-full-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-touch{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-touch{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-touch{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-touch{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-touch{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-touch{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-touch{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-touch{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-touch{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-touch{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-touch{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-touch{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-touch{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-touch{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-touch{margin-left:80%}html.theme--documenter-dark .column.is-0-touch{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-touch{margin-left:0%}html.theme--documenter-dark .column.is-1-touch{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-touch{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-touch{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-touch{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-touch{margin-left:25%}html.theme--documenter-dark .column.is-4-touch{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-touch{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-touch{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-touch{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-touch{margin-left:50%}html.theme--documenter-dark .column.is-7-touch{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-touch{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-touch{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-touch{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-touch{margin-left:75%}html.theme--documenter-dark .column.is-10-touch{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-touch{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-touch{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-touch{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){html.theme--documenter-dark .column.is-narrow-desktop{flex:none;width:unset}html.theme--documenter-dark .column.is-full-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-desktop{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-desktop{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-desktop{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-desktop{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-desktop{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-desktop{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-desktop{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-desktop{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-desktop{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-desktop{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-desktop{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-desktop{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-desktop{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-desktop{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-desktop{margin-left:80%}html.theme--documenter-dark .column.is-0-desktop{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-desktop{margin-left:0%}html.theme--documenter-dark .column.is-1-desktop{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-desktop{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-desktop{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-desktop{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-desktop{margin-left:25%}html.theme--documenter-dark .column.is-4-desktop{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-desktop{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-desktop{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-desktop{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-desktop{margin-left:50%}html.theme--documenter-dark .column.is-7-desktop{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-desktop{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-desktop{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-desktop{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-desktop{margin-left:75%}html.theme--documenter-dark .column.is-10-desktop{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-desktop{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-desktop{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-desktop{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){html.theme--documenter-dark .column.is-narrow-widescreen{flex:none;width:unset}html.theme--documenter-dark .column.is-full-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-widescreen{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-widescreen{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-widescreen{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-widescreen{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-widescreen{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-widescreen{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-widescreen{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-widescreen{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-widescreen{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-widescreen{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-widescreen{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-widescreen{margin-left:80%}html.theme--documenter-dark .column.is-0-widescreen{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-widescreen{margin-left:0%}html.theme--documenter-dark .column.is-1-widescreen{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-widescreen{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-widescreen{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-widescreen{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-4-widescreen{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-widescreen{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-widescreen{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-widescreen{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-7-widescreen{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-widescreen{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-widescreen{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-widescreen{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-10-widescreen{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-widescreen{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-widescreen{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-widescreen{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){html.theme--documenter-dark .column.is-narrow-fullhd{flex:none;width:unset}html.theme--documenter-dark .column.is-full-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-fullhd{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-fullhd{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-fullhd{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-fullhd{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-fullhd{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-fullhd{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-fullhd{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-fullhd{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-fullhd{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-fullhd{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-fullhd{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-fullhd{margin-left:80%}html.theme--documenter-dark .column.is-0-fullhd{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-fullhd{margin-left:0%}html.theme--documenter-dark .column.is-1-fullhd{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-fullhd{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-fullhd{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-fullhd{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-4-fullhd{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-fullhd{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-fullhd{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-fullhd{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-7-fullhd{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-fullhd{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-fullhd{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-fullhd{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-10-fullhd{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-fullhd{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-fullhd{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-fullhd{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-fullhd{margin-left:100%}}html.theme--documenter-dark .columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .columns:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}html.theme--documenter-dark .columns.is-centered{justify-content:center}html.theme--documenter-dark .columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}html.theme--documenter-dark .columns.is-gapless>.column{margin:0;padding:0 !important}html.theme--documenter-dark .columns.is-gapless:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .columns.is-gapless:last-child{margin-bottom:0}html.theme--documenter-dark .columns.is-mobile{display:flex}html.theme--documenter-dark .columns.is-multiline{flex-wrap:wrap}html.theme--documenter-dark .columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-desktop{display:flex}}html.theme--documenter-dark .columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}html.theme--documenter-dark .columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}html.theme--documenter-dark .columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-0-fullhd{--columnGap: 0rem}}html.theme--documenter-dark .columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-1-fullhd{--columnGap: .25rem}}html.theme--documenter-dark .columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-2-fullhd{--columnGap: .5rem}}html.theme--documenter-dark .columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-3-fullhd{--columnGap: .75rem}}html.theme--documenter-dark .columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-4-fullhd{--columnGap: 1rem}}html.theme--documenter-dark .columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}html.theme--documenter-dark .columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}html.theme--documenter-dark .columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}html.theme--documenter-dark .columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-8-fullhd{--columnGap: 2rem}}html.theme--documenter-dark .tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}html.theme--documenter-dark .tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .tile.is-ancestor:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .tile.is-ancestor:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .tile.is-child{margin:0 !important}html.theme--documenter-dark .tile.is-parent{padding:.75rem}html.theme--documenter-dark .tile.is-vertical{flex-direction:column}html.theme--documenter-dark .tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{html.theme--documenter-dark .tile:not(.is-child){display:flex}html.theme--documenter-dark .tile.is-1{flex:none;width:8.33333337%}html.theme--documenter-dark .tile.is-2{flex:none;width:16.66666674%}html.theme--documenter-dark .tile.is-3{flex:none;width:25%}html.theme--documenter-dark .tile.is-4{flex:none;width:33.33333337%}html.theme--documenter-dark .tile.is-5{flex:none;width:41.66666674%}html.theme--documenter-dark .tile.is-6{flex:none;width:50%}html.theme--documenter-dark .tile.is-7{flex:none;width:58.33333337%}html.theme--documenter-dark .tile.is-8{flex:none;width:66.66666674%}html.theme--documenter-dark .tile.is-9{flex:none;width:75%}html.theme--documenter-dark .tile.is-10{flex:none;width:83.33333337%}html.theme--documenter-dark .tile.is-11{flex:none;width:91.66666674%}html.theme--documenter-dark .tile.is-12{flex:none;width:100%}}html.theme--documenter-dark .hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}html.theme--documenter-dark .hero .navbar{background:none}html.theme--documenter-dark .hero .tabs ul{border-bottom:none}html.theme--documenter-dark .hero.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-white strong{color:inherit}html.theme--documenter-dark .hero.is-white .title{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .subtitle{color:rgba(10,10,10,0.9)}html.theme--documenter-dark .hero.is-white .subtitle a:not(.button),html.theme--documenter-dark .hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-white .navbar-menu{background-color:#fff}}html.theme--documenter-dark .hero.is-white .navbar-item,html.theme--documenter-dark .hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}html.theme--documenter-dark .hero.is-white a.navbar-item:hover,html.theme--documenter-dark .hero.is-white a.navbar-item.is-active,html.theme--documenter-dark .hero.is-white .navbar-link:hover,html.theme--documenter-dark .hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}html.theme--documenter-dark .hero.is-white .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-white .tabs li.is-active a{color:#fff !important;opacity:1}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}html.theme--documenter-dark .hero.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-black strong{color:inherit}html.theme--documenter-dark .hero.is-black .title{color:#fff}html.theme--documenter-dark .hero.is-black .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-black .subtitle a:not(.button),html.theme--documenter-dark .hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-black .navbar-menu{background-color:#0a0a0a}}html.theme--documenter-dark .hero.is-black .navbar-item,html.theme--documenter-dark .hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-black a.navbar-item:hover,html.theme--documenter-dark .hero.is-black a.navbar-item.is-active,html.theme--documenter-dark .hero.is-black .navbar-link:hover,html.theme--documenter-dark .hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .hero.is-black .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-black .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-black .tabs li.is-active a{color:#0a0a0a !important;opacity:1}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}html.theme--documenter-dark .hero.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-light strong{color:inherit}html.theme--documenter-dark .hero.is-light .title{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .subtitle{color:rgba(0,0,0,0.9)}html.theme--documenter-dark .hero.is-light .subtitle a:not(.button),html.theme--documenter-dark .hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-light .navbar-menu{background-color:#ecf0f1}}html.theme--documenter-dark .hero.is-light .navbar-item,html.theme--documenter-dark .hero.is-light .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a.navbar-item:hover,html.theme--documenter-dark .hero.is-light a.navbar-item.is-active,html.theme--documenter-dark .hero.is-light .navbar-link:hover,html.theme--documenter-dark .hero.is-light .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}html.theme--documenter-dark .hero.is-light .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-light .tabs li.is-active a{color:#ecf0f1 !important;opacity:1}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .hero.is-light.is-bold{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}}html.theme--documenter-dark .hero.is-dark,html.theme--documenter-dark .content kbd.hero{background-color:#282f2f;color:#fff}html.theme--documenter-dark .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-dark strong,html.theme--documenter-dark .content kbd.hero strong{color:inherit}html.theme--documenter-dark .hero.is-dark .title,html.theme--documenter-dark .content kbd.hero .title{color:#fff}html.theme--documenter-dark .hero.is-dark .subtitle,html.theme--documenter-dark .content kbd.hero .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-dark .subtitle a:not(.button),html.theme--documenter-dark .content kbd.hero .subtitle a:not(.button),html.theme--documenter-dark .hero.is-dark .subtitle strong,html.theme--documenter-dark .content kbd.hero .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-dark .navbar-menu,html.theme--documenter-dark .content kbd.hero .navbar-menu{background-color:#282f2f}}html.theme--documenter-dark .hero.is-dark .navbar-item,html.theme--documenter-dark .content kbd.hero .navbar-item,html.theme--documenter-dark .hero.is-dark .navbar-link,html.theme--documenter-dark .content kbd.hero .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-dark a.navbar-item:hover,html.theme--documenter-dark .content kbd.hero a.navbar-item:hover,html.theme--documenter-dark .hero.is-dark a.navbar-item.is-active,html.theme--documenter-dark .content kbd.hero a.navbar-item.is-active,html.theme--documenter-dark .hero.is-dark .navbar-link:hover,html.theme--documenter-dark .content kbd.hero .navbar-link:hover,html.theme--documenter-dark .hero.is-dark .navbar-link.is-active,html.theme--documenter-dark .content kbd.hero .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .hero.is-dark .tabs a,html.theme--documenter-dark .content kbd.hero .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-dark .tabs a:hover,html.theme--documenter-dark .content kbd.hero .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-dark .tabs li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs li.is-active a{color:#282f2f !important;opacity:1}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#282f2f}html.theme--documenter-dark .hero.is-dark.is-bold,html.theme--documenter-dark .content kbd.hero.is-bold{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-dark.is-bold .navbar-menu,html.theme--documenter-dark .content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}}html.theme--documenter-dark .hero.is-primary,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-primary strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink strong{color:inherit}html.theme--documenter-dark .hero.is-primary .title,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .title{color:#fff}html.theme--documenter-dark .hero.is-primary .subtitle,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-primary .subtitle a:not(.button),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),html.theme--documenter-dark .hero.is-primary .subtitle strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-primary .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#375a7f}}html.theme--documenter-dark .hero.is-primary .navbar-item,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-item,html.theme--documenter-dark .hero.is-primary .navbar-link,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-primary a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,html.theme--documenter-dark .hero.is-primary a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,html.theme--documenter-dark .hero.is-primary .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link:hover,html.theme--documenter-dark .hero.is-primary .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .hero.is-primary .tabs a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-primary .tabs a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-primary .tabs li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{color:#375a7f !important;opacity:1}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#375a7f}html.theme--documenter-dark .hero.is-primary.is-bold,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-primary.is-bold .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}}html.theme--documenter-dark .hero.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-link strong{color:inherit}html.theme--documenter-dark .hero.is-link .title{color:#fff}html.theme--documenter-dark .hero.is-link .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-link .subtitle a:not(.button),html.theme--documenter-dark .hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-link .navbar-menu{background-color:#1abc9c}}html.theme--documenter-dark .hero.is-link .navbar-item,html.theme--documenter-dark .hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-link a.navbar-item:hover,html.theme--documenter-dark .hero.is-link a.navbar-item.is-active,html.theme--documenter-dark .hero.is-link .navbar-link:hover,html.theme--documenter-dark .hero.is-link .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .hero.is-link .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-link .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-link .tabs li.is-active a{color:#1abc9c !important;opacity:1}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#1abc9c}html.theme--documenter-dark .hero.is-link.is-bold{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}}html.theme--documenter-dark .hero.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-info strong{color:inherit}html.theme--documenter-dark .hero.is-info .title{color:#fff}html.theme--documenter-dark .hero.is-info .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-info .subtitle a:not(.button),html.theme--documenter-dark .hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-info .navbar-menu{background-color:#024c7d}}html.theme--documenter-dark .hero.is-info .navbar-item,html.theme--documenter-dark .hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-info a.navbar-item:hover,html.theme--documenter-dark .hero.is-info a.navbar-item.is-active,html.theme--documenter-dark .hero.is-info .navbar-link:hover,html.theme--documenter-dark .hero.is-info .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .hero.is-info .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-info .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-info .tabs li.is-active a{color:#024c7d !important;opacity:1}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#024c7d}html.theme--documenter-dark .hero.is-info.is-bold{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}}html.theme--documenter-dark .hero.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-success strong{color:inherit}html.theme--documenter-dark .hero.is-success .title{color:#fff}html.theme--documenter-dark .hero.is-success .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-success .subtitle a:not(.button),html.theme--documenter-dark .hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-success .navbar-menu{background-color:#008438}}html.theme--documenter-dark .hero.is-success .navbar-item,html.theme--documenter-dark .hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-success a.navbar-item:hover,html.theme--documenter-dark .hero.is-success a.navbar-item.is-active,html.theme--documenter-dark .hero.is-success .navbar-link:hover,html.theme--documenter-dark .hero.is-success .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .hero.is-success .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-success .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-success .tabs li.is-active a{color:#008438 !important;opacity:1}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#008438}html.theme--documenter-dark .hero.is-success.is-bold{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}}html.theme--documenter-dark .hero.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-warning strong{color:inherit}html.theme--documenter-dark .hero.is-warning .title{color:#fff}html.theme--documenter-dark .hero.is-warning .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-warning .subtitle a:not(.button),html.theme--documenter-dark .hero.is-warning .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-warning .navbar-menu{background-color:#ad8100}}html.theme--documenter-dark .hero.is-warning .navbar-item,html.theme--documenter-dark .hero.is-warning .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-warning a.navbar-item:hover,html.theme--documenter-dark .hero.is-warning a.navbar-item.is-active,html.theme--documenter-dark .hero.is-warning .navbar-link:hover,html.theme--documenter-dark .hero.is-warning .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .hero.is-warning .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-warning .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-warning .tabs li.is-active a{color:#ad8100 !important;opacity:1}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ad8100}html.theme--documenter-dark .hero.is-warning.is-bold{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}}html.theme--documenter-dark .hero.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-danger strong{color:inherit}html.theme--documenter-dark .hero.is-danger .title{color:#fff}html.theme--documenter-dark .hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-danger .subtitle a:not(.button),html.theme--documenter-dark .hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-danger .navbar-menu{background-color:#9e1b0d}}html.theme--documenter-dark .hero.is-danger .navbar-item,html.theme--documenter-dark .hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-danger a.navbar-item:hover,html.theme--documenter-dark .hero.is-danger a.navbar-item.is-active,html.theme--documenter-dark .hero.is-danger .navbar-link:hover,html.theme--documenter-dark .hero.is-danger .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .hero.is-danger .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-danger .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-danger .tabs li.is-active a{color:#9e1b0d !important;opacity:1}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#9e1b0d}html.theme--documenter-dark .hero.is-danger.is-bold{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}}html.theme--documenter-dark .hero.is-small .hero-body,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding:1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-large .hero-body{padding:18rem 6rem}}html.theme--documenter-dark .hero.is-halfheight .hero-body,html.theme--documenter-dark .hero.is-fullheight .hero-body,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}html.theme--documenter-dark .hero.is-halfheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .hero.is-halfheight{min-height:50vh}html.theme--documenter-dark .hero.is-fullheight{min-height:100vh}html.theme--documenter-dark .hero-video{overflow:hidden}html.theme--documenter-dark .hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}html.theme--documenter-dark .hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-video{display:none}}html.theme--documenter-dark .hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-buttons .button{display:flex}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-buttons{display:flex;justify-content:center}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-right:1.5rem}}html.theme--documenter-dark .hero-head,html.theme--documenter-dark .hero-foot{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-body{padding:3rem 3rem}}html.theme--documenter-dark .section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){html.theme--documenter-dark .section{padding:3rem 3rem}html.theme--documenter-dark .section.is-medium{padding:9rem 4.5rem}html.theme--documenter-dark .section.is-large{padding:18rem 6rem}}html.theme--documenter-dark .footer{background-color:#282f2f;padding:3rem 1.5rem 6rem}html.theme--documenter-dark hr{height:1px}html.theme--documenter-dark h6{text-transform:uppercase;letter-spacing:0.5px}html.theme--documenter-dark .hero{background-color:#343c3d}html.theme--documenter-dark a{transition:all 200ms ease}html.theme--documenter-dark .button{transition:all 200ms ease;border-width:1px;color:#fff}html.theme--documenter-dark .button.is-active,html.theme--documenter-dark .button.is-focused,html.theme--documenter-dark .button:active,html.theme--documenter-dark .button:focus{box-shadow:0 0 0 2px rgba(140,155,157,0.5)}html.theme--documenter-dark .button.is-white.is-hovered,html.theme--documenter-dark .button.is-white:hover{background-color:#fff}html.theme--documenter-dark .button.is-white.is-active,html.theme--documenter-dark .button.is-white.is-focused,html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white:focus{border-color:#fff;box-shadow:0 0 0 2px rgba(255,255,255,0.5)}html.theme--documenter-dark .button.is-black.is-hovered,html.theme--documenter-dark .button.is-black:hover{background-color:#1d1d1d}html.theme--documenter-dark .button.is-black.is-active,html.theme--documenter-dark .button.is-black.is-focused,html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black:focus{border-color:#0a0a0a;box-shadow:0 0 0 2px rgba(10,10,10,0.5)}html.theme--documenter-dark .button.is-light.is-hovered,html.theme--documenter-dark .button.is-light:hover{background-color:#fff}html.theme--documenter-dark .button.is-light.is-active,html.theme--documenter-dark .button.is-light.is-focused,html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light:focus{border-color:#ecf0f1;box-shadow:0 0 0 2px rgba(236,240,241,0.5)}html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered,html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover{background-color:#3a4344}html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused,html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus{border-color:#282f2f;box-shadow:0 0 0 2px rgba(40,47,47,0.5)}html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover{background-color:#436d9a}html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink,html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus{border-color:#375a7f;box-shadow:0 0 0 2px rgba(55,90,127,0.5)}html.theme--documenter-dark .button.is-link.is-hovered,html.theme--documenter-dark .button.is-link:hover{background-color:#1fdeb8}html.theme--documenter-dark .button.is-link.is-active,html.theme--documenter-dark .button.is-link.is-focused,html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link:focus{border-color:#1abc9c;box-shadow:0 0 0 2px rgba(26,188,156,0.5)}html.theme--documenter-dark .button.is-info.is-hovered,html.theme--documenter-dark .button.is-info:hover{background-color:#0363a3}html.theme--documenter-dark .button.is-info.is-active,html.theme--documenter-dark .button.is-info.is-focused,html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info:focus{border-color:#024c7d;box-shadow:0 0 0 2px rgba(2,76,125,0.5)}html.theme--documenter-dark .button.is-success.is-hovered,html.theme--documenter-dark .button.is-success:hover{background-color:#00aa48}html.theme--documenter-dark .button.is-success.is-active,html.theme--documenter-dark .button.is-success.is-focused,html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success:focus{border-color:#008438;box-shadow:0 0 0 2px rgba(0,132,56,0.5)}html.theme--documenter-dark .button.is-warning.is-hovered,html.theme--documenter-dark .button.is-warning:hover{background-color:#d39e00}html.theme--documenter-dark .button.is-warning.is-active,html.theme--documenter-dark .button.is-warning.is-focused,html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning:focus{border-color:#ad8100;box-shadow:0 0 0 2px rgba(173,129,0,0.5)}html.theme--documenter-dark .button.is-danger.is-hovered,html.theme--documenter-dark .button.is-danger:hover{background-color:#c12110}html.theme--documenter-dark .button.is-danger.is-active,html.theme--documenter-dark .button.is-danger.is-focused,html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger:focus{border-color:#9e1b0d;box-shadow:0 0 0 2px rgba(158,27,13,0.5)}html.theme--documenter-dark .label{color:#dbdee0}html.theme--documenter-dark .button,html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .select,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea{height:2.5em}html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .textarea{transition:all 200ms ease;box-shadow:none;border-width:1px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .select:after,html.theme--documenter-dark .select select{border-width:1px}html.theme--documenter-dark .control.has-addons .button,html.theme--documenter-dark .control.has-addons .input,html.theme--documenter-dark .control.has-addons #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-addons form.docs-search>input,html.theme--documenter-dark .control.has-addons .select{margin-right:-1px}html.theme--documenter-dark .notification{background-color:#343c3d}html.theme--documenter-dark .card{box-shadow:none;border:1px solid #343c3d;background-color:#282f2f;border-radius:.4em}html.theme--documenter-dark .card .card-image img{border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-header{box-shadow:none;background-color:rgba(18,18,18,0.2);border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-footer{background-color:rgba(18,18,18,0.2)}html.theme--documenter-dark .card .card-footer,html.theme--documenter-dark .card .card-footer-item{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .notification.is-white a:not(.button){color:#0a0a0a;text-decoration:underline}html.theme--documenter-dark .notification.is-black a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-light a:not(.button){color:rgba(0,0,0,0.7);text-decoration:underline}html.theme--documenter-dark .notification.is-dark a:not(.button),html.theme--documenter-dark .content kbd.notification a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-primary a:not(.button),html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-link a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-info a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-success a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-warning a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-danger a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .tag,html.theme--documenter-dark .content kbd,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{border-radius:.4em}html.theme--documenter-dark .menu-list a{transition:all 300ms ease}html.theme--documenter-dark .modal-card-body{background-color:#282f2f}html.theme--documenter-dark .modal-card-foot,html.theme--documenter-dark .modal-card-head{border-color:#343c3d}html.theme--documenter-dark .message-header{font-weight:700;background-color:#343c3d;color:#fff}html.theme--documenter-dark .message-body{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .navbar{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent{background:none}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar .navbar-menu{background-color:#375a7f;border-radius:0 0 .4em .4em}}html.theme--documenter-dark .hero .navbar,html.theme--documenter-dark body>.navbar{border-radius:0}html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous{border-width:1px}html.theme--documenter-dark .panel-block,html.theme--documenter-dark .panel-heading,html.theme--documenter-dark .panel-tabs{border-width:1px}html.theme--documenter-dark .panel-block:first-child,html.theme--documenter-dark .panel-heading:first-child,html.theme--documenter-dark .panel-tabs:first-child{border-top-width:1px}html.theme--documenter-dark .panel-heading{font-weight:700}html.theme--documenter-dark .panel-tabs a{border-width:1px;margin-bottom:-1px}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#17a689}html.theme--documenter-dark .panel-block:hover{color:#1dd2af}html.theme--documenter-dark .panel-block:hover .panel-icon{color:#1dd2af}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#17a689}html.theme--documenter-dark .tabs a{border-bottom-width:1px;margin-bottom:-1px}html.theme--documenter-dark .tabs ul{border-bottom-width:1px}html.theme--documenter-dark .tabs.is-boxed a{border-width:1px}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#1f2424}html.theme--documenter-dark .tabs.is-toggle li a{border-width:1px;margin-bottom:0}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .hero.is-white .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-black .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-light .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-dark .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .content kbd.hero .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-primary .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-link .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-info .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-success .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-warning .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-danger .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark h1 .docs-heading-anchor,html.theme--documenter-dark h1 .docs-heading-anchor:hover,html.theme--documenter-dark h1 .docs-heading-anchor:visited,html.theme--documenter-dark h2 .docs-heading-anchor,html.theme--documenter-dark h2 .docs-heading-anchor:hover,html.theme--documenter-dark h2 .docs-heading-anchor:visited,html.theme--documenter-dark h3 .docs-heading-anchor,html.theme--documenter-dark h3 .docs-heading-anchor:hover,html.theme--documenter-dark h3 .docs-heading-anchor:visited,html.theme--documenter-dark h4 .docs-heading-anchor,html.theme--documenter-dark h4 .docs-heading-anchor:hover,html.theme--documenter-dark h4 .docs-heading-anchor:visited,html.theme--documenter-dark h5 .docs-heading-anchor,html.theme--documenter-dark h5 .docs-heading-anchor:hover,html.theme--documenter-dark h5 .docs-heading-anchor:visited,html.theme--documenter-dark h6 .docs-heading-anchor,html.theme--documenter-dark h6 .docs-heading-anchor:hover,html.theme--documenter-dark h6 .docs-heading-anchor:visited{color:#f2f2f2}html.theme--documenter-dark h1 .docs-heading-anchor-permalink,html.theme--documenter-dark h2 .docs-heading-anchor-permalink,html.theme--documenter-dark h3 .docs-heading-anchor-permalink,html.theme--documenter-dark h4 .docs-heading-anchor-permalink,html.theme--documenter-dark h5 .docs-heading-anchor-permalink,html.theme--documenter-dark h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}html.theme--documenter-dark h1 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h2 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h3 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h4 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h5 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f0c1"}html.theme--documenter-dark h1:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h2:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h3:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h4:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h5:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h6:hover .docs-heading-anchor-permalink{visibility:visible}html.theme--documenter-dark .docs-light-only{display:none !important}html.theme--documenter-dark pre{position:relative;overflow:hidden}html.theme--documenter-dark pre code,html.theme--documenter-dark pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}html.theme--documenter-dark pre code:first-of-type,html.theme--documenter-dark pre code.hljs:first-of-type{padding-top:0.5rem !important}html.theme--documenter-dark pre code:last-of-type,html.theme--documenter-dark pre code.hljs:last-of-type{padding-bottom:0.5rem !important}html.theme--documenter-dark pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 6 Free";color:#fff;cursor:pointer;text-align:center}html.theme--documenter-dark pre .copy-button:focus,html.theme--documenter-dark pre .copy-button:hover{opacity:1;background:rgba(255,255,255,0.1);color:#1abc9c}html.theme--documenter-dark pre .copy-button.success{color:#259a12;opacity:1}html.theme--documenter-dark pre .copy-button.error{color:#cb3c33;opacity:1}html.theme--documenter-dark pre:hover .copy-button{opacity:1}html.theme--documenter-dark .admonition{background-color:#282f2f;border-style:solid;border-width:1px;border-color:#5e6d6f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .admonition strong{color:currentColor}html.theme--documenter-dark .admonition.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}html.theme--documenter-dark .admonition.is-medium{font-size:1.25rem}html.theme--documenter-dark .admonition.is-large{font-size:1.5rem}html.theme--documenter-dark .admonition.is-default{background-color:#282f2f;border-color:#5e6d6f}html.theme--documenter-dark .admonition.is-default>.admonition-header{background-color:#5e6d6f;color:#fff}html.theme--documenter-dark .admonition.is-default>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-info{background-color:#282f2f;border-color:#024c7d}html.theme--documenter-dark .admonition.is-info>.admonition-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .admonition.is-info>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-success{background-color:#282f2f;border-color:#008438}html.theme--documenter-dark .admonition.is-success>.admonition-header{background-color:#008438;color:#fff}html.theme--documenter-dark .admonition.is-success>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-warning{background-color:#282f2f;border-color:#ad8100}html.theme--documenter-dark .admonition.is-warning>.admonition-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .admonition.is-warning>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-danger{background-color:#282f2f;border-color:#9e1b0d}html.theme--documenter-dark .admonition.is-danger>.admonition-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .admonition.is-danger>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-compat{background-color:#282f2f;border-color:#137886}html.theme--documenter-dark .admonition.is-compat>.admonition-header{background-color:#137886;color:#fff}html.theme--documenter-dark .admonition.is-compat>.admonition-body{color:#fff}html.theme--documenter-dark .admonition-header{color:#fff;background-color:#5e6d6f;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}html.theme--documenter-dark .admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}html.theme--documenter-dark details.admonition.is-details>.admonition-header{list-style:none}html.theme--documenter-dark details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}html.theme--documenter-dark details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}html.theme--documenter-dark .admonition-body{color:#fff;padding:0.5rem .75rem}html.theme--documenter-dark .admonition-body pre{background-color:#282f2f}html.theme--documenter-dark .admonition-body code{background-color:rgba(255,255,255,0.05)}html.theme--documenter-dark .docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #5e6d6f;box-shadow:none;max-width:100%}html.theme--documenter-dark .docstring>header{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#282f2f;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #5e6d6f;overflow:auto}html.theme--documenter-dark .docstring>header code{background-color:transparent}html.theme--documenter-dark .docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}html.theme--documenter-dark .docstring>header .docstring-binding{margin-right:0.3em}html.theme--documenter-dark .docstring>header .docstring-category{margin-left:0.3em}html.theme--documenter-dark .docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>section:last-child{border-bottom:none}html.theme--documenter-dark .docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}html.theme--documenter-dark .docstring>section>a.docs-sourcelink:focus{opacity:1 !important}html.theme--documenter-dark .docstring:hover>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring>section:hover a.docs-sourcelink{opacity:1}html.theme--documenter-dark .documenter-example-output{background-color:#1f2424}html.theme--documenter-dark .outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#282f2f;color:#fff;border-bottom:3px solid #9e1b0d;padding:10px 35px;text-align:center;font-size:15px}html.theme--documenter-dark .outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}html.theme--documenter-dark .outdated-warning-overlay a{color:#1abc9c}html.theme--documenter-dark .outdated-warning-overlay a:hover{color:#1dd2af}html.theme--documenter-dark .content pre{border:1px solid #5e6d6f}html.theme--documenter-dark .content code{font-weight:inherit}html.theme--documenter-dark .content a code{color:#1abc9c}html.theme--documenter-dark .content a:hover code{color:#1dd2af}html.theme--documenter-dark .content h1 code,html.theme--documenter-dark .content h2 code,html.theme--documenter-dark .content h3 code,html.theme--documenter-dark .content h4 code,html.theme--documenter-dark .content h5 code,html.theme--documenter-dark .content h6 code{color:#f2f2f2}html.theme--documenter-dark .content table{display:block;width:initial;max-width:100%;overflow-x:auto}html.theme--documenter-dark .content blockquote>ul:first-child,html.theme--documenter-dark .content blockquote>ol:first-child,html.theme--documenter-dark .content .admonition-body>ul:first-child,html.theme--documenter-dark .content .admonition-body>ol:first-child{margin-top:0}html.theme--documenter-dark pre,html.theme--documenter-dark code{font-variant-ligatures:no-contextual}html.theme--documenter-dark .breadcrumb a.is-disabled{cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb a.is-disabled,html.theme--documenter-dark .breadcrumb a.is-disabled:hover{color:#f2f2f2}html.theme--documenter-dark .hljs{background:initial !important}html.theme--documenter-dark .katex .katex-mathml{top:0;right:0}html.theme--documenter-dark .katex-display,html.theme--documenter-dark mjx-container,html.theme--documenter-dark .MathJax_Display{margin:0.5em 0 !important}html.theme--documenter-dark html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}html.theme--documenter-dark li.no-marker{list-style:none}html.theme--documenter-dark #documenter .docs-main>article{overflow-wrap:break-word}html.theme--documenter-dark #documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main{width:100%}html.theme--documenter-dark #documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-main>header,html.theme--documenter-dark #documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar{background-color:#1f2424;border-bottom:1px solid #5e6d6f;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1;overflow-x:hidden}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-icon,html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #171717;transition-duration:0.7s;-webkit-transition-duration:0.7s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}html.theme--documenter-dark #documenter .docs-main section.footnotes{border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-main section.footnotes li .tag:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .content kbd:first-child,html.theme--documenter-dark .content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}html.theme--documenter-dark #documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #5e6d6f;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage,html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}html.theme--documenter-dark #documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}html.theme--documenter-dark #documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}html.theme--documenter-dark #documenter .docs-sidebar{display:flex;flex-direction:column;color:#fff;background-color:#282f2f;border-right:1px solid #5e6d6f;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}html.theme--documenter-dark #documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #171717}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar{left:0;top:0}}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a,html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a:hover{color:#fff}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector{border-top:1px solid #5e6d6f;display:none;padding:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector.visible{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #5e6d6f;padding-bottom:1.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f054"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#fff;background:#282f2f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu a.tocitem:hover,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#fff;background-color:#32393a}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #5e6d6f;border-bottom:1px solid #5e6d6f;background-color:#1f2424}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#1f2424;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#32393a;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{width:14.4rem}html.theme--documenter-dark #documenter .docs-sidebar #documenter-search-query{color:#868c98;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}html.theme--documenter-dark kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(245,245,245,0.6);box-shadow:0 2px 0 1px rgba(245,245,245,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}html.theme--documenter-dark .search-min-width-50{min-width:50%}html.theme--documenter-dark .search-min-height-100{min-height:100%}html.theme--documenter-dark .search-modal-card-body{max-height:calc(100vh - 15rem)}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333;background-color:#f1f5f9}html.theme--documenter-dark .search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}html.theme--documenter-dark .search-filter:hover,html.theme--documenter-dark .search-filter:focus{color:#333}html.theme--documenter-dark .search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}html.theme--documenter-dark .search-filter-selected:hover,html.theme--documenter-dark .search-filter-selected:focus{color:#f5f5f5}html.theme--documenter-dark .search-result-highlight{background-color:#ffdd57;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .search-result-title{width:85%;color:#f5f5f5}html.theme--documenter-dark .search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-thumb,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-track,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem}html.theme--documenter-dark .gap-8{gap:2rem}html.theme--documenter-dark{background-color:#1f2424;font-size:16px;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark .ansi span.sgr1{font-weight:bolder}html.theme--documenter-dark .ansi span.sgr2{font-weight:lighter}html.theme--documenter-dark .ansi span.sgr3{font-style:italic}html.theme--documenter-dark .ansi span.sgr4{text-decoration:underline}html.theme--documenter-dark .ansi span.sgr7{color:#1f2424;background-color:#fff}html.theme--documenter-dark .ansi span.sgr8{color:transparent}html.theme--documenter-dark .ansi span.sgr8 span{color:transparent}html.theme--documenter-dark .ansi span.sgr9{text-decoration:line-through}html.theme--documenter-dark .ansi span.sgr30{color:#242424}html.theme--documenter-dark .ansi span.sgr31{color:#f6705f}html.theme--documenter-dark .ansi span.sgr32{color:#4fb43a}html.theme--documenter-dark .ansi span.sgr33{color:#f4c72f}html.theme--documenter-dark .ansi span.sgr34{color:#7587f0}html.theme--documenter-dark .ansi span.sgr35{color:#bc89d3}html.theme--documenter-dark .ansi span.sgr36{color:#49b6ca}html.theme--documenter-dark .ansi span.sgr37{color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr40{background-color:#242424}html.theme--documenter-dark .ansi span.sgr41{background-color:#f6705f}html.theme--documenter-dark .ansi span.sgr42{background-color:#4fb43a}html.theme--documenter-dark .ansi span.sgr43{background-color:#f4c72f}html.theme--documenter-dark .ansi span.sgr44{background-color:#7587f0}html.theme--documenter-dark .ansi span.sgr45{background-color:#bc89d3}html.theme--documenter-dark .ansi span.sgr46{background-color:#49b6ca}html.theme--documenter-dark .ansi span.sgr47{background-color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr90{color:#92a0a2}html.theme--documenter-dark .ansi span.sgr91{color:#ff8674}html.theme--documenter-dark .ansi span.sgr92{color:#79d462}html.theme--documenter-dark .ansi span.sgr93{color:#ffe76b}html.theme--documenter-dark .ansi span.sgr94{color:#8a98ff}html.theme--documenter-dark .ansi span.sgr95{color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr96{color:#6bc8db}html.theme--documenter-dark .ansi span.sgr97{color:#ecf0f1}html.theme--documenter-dark .ansi span.sgr100{background-color:#92a0a2}html.theme--documenter-dark .ansi span.sgr101{background-color:#ff8674}html.theme--documenter-dark .ansi span.sgr102{background-color:#79d462}html.theme--documenter-dark .ansi span.sgr103{background-color:#ffe76b}html.theme--documenter-dark .ansi span.sgr104{background-color:#8a98ff}html.theme--documenter-dark .ansi span.sgr105{background-color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr106{background-color:#6bc8db}html.theme--documenter-dark .ansi span.sgr107{background-color:#ecf0f1}html.theme--documenter-dark code.language-julia-repl>span.hljs-meta{color:#4fb43a;font-weight:bolder}html.theme--documenter-dark .hljs{background:#2b2b2b;color:#f8f8f2}html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-quote{color:#d4d0ab}html.theme--documenter-dark .hljs-variable,html.theme--documenter-dark .hljs-template-variable,html.theme--documenter-dark .hljs-tag,html.theme--documenter-dark .hljs-name,html.theme--documenter-dark .hljs-selector-id,html.theme--documenter-dark .hljs-selector-class,html.theme--documenter-dark .hljs-regexp,html.theme--documenter-dark .hljs-deletion{color:#ffa07a}html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-link{color:#f5ab35}html.theme--documenter-dark .hljs-attribute{color:#ffd700}html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-addition{color:#abe338}html.theme--documenter-dark .hljs-title,html.theme--documenter-dark .hljs-section{color:#00e0e0}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{color:#dcc6e0}html.theme--documenter-dark .hljs-emphasis{font-style:italic}html.theme--documenter-dark .hljs-strong{font-weight:bold}@media screen and (-ms-high-contrast: active){html.theme--documenter-dark .hljs-addition,html.theme--documenter-dark .hljs-attribute,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-link,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-quote{color:highlight}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{font-weight:bold}}html.theme--documenter-dark .hljs-subst{color:#f8f8f2}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333 !important;background-color:#f1f5f9 !important}html.theme--documenter-dark .search-result-title{color:whitesmoke}html.theme--documenter-dark .search-result-highlight{background-color:greenyellow;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f50}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem} diff --git a/v0.16.12/assets/themes/documenter-light.css b/v0.16.12/assets/themes/documenter-light.css new file mode 100644 index 000000000..07f9d0883 --- /dev/null +++ b/v0.16.12/assets/themes/documenter-light.css @@ -0,0 +1,9 @@ +.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.file-cta,.file-name,.select select,.textarea,.input,#documenter .docs-sidebar form.docs-search>input,.button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.5em - 1px);padding-left:calc(0.75em - 1px);padding-right:calc(0.75em - 1px);padding-top:calc(0.5em - 1px);position:relative;vertical-align:top}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus,.pagination-ellipsis:focus,.file-cta:focus,.file-name:focus,.select select:focus,.textarea:focus,.input:focus,#documenter .docs-sidebar form.docs-search>input:focus,.button:focus,.is-focused.pagination-previous,.is-focused.pagination-next,.is-focused.pagination-link,.is-focused.pagination-ellipsis,.is-focused.file-cta,.is-focused.file-name,.select select.is-focused,.is-focused.textarea,.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-focused.button,.pagination-previous:active,.pagination-next:active,.pagination-link:active,.pagination-ellipsis:active,.file-cta:active,.file-name:active,.select select:active,.textarea:active,.input:active,#documenter .docs-sidebar form.docs-search>input:active,.button:active,.is-active.pagination-previous,.is-active.pagination-next,.is-active.pagination-link,.is-active.pagination-ellipsis,.is-active.file-cta,.is-active.file-name,.select select.is-active,.is-active.textarea,.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.is-active.button{outline:none}.pagination-previous[disabled],.pagination-next[disabled],.pagination-link[disabled],.pagination-ellipsis[disabled],.file-cta[disabled],.file-name[disabled],.select select[disabled],.textarea[disabled],.input[disabled],#documenter .docs-sidebar form.docs-search>input[disabled],.button[disabled],fieldset[disabled] .pagination-previous,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .select select,.select fieldset[disabled] select,fieldset[disabled] .textarea,fieldset[disabled] .input,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input,fieldset[disabled] .button{cursor:not-allowed}.tabs,.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.breadcrumb,.file,.button,.is-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid rgba(0,0,0,0);border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:0.625em;margin-top:-0.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:0.625em}.admonition:not(:last-child),.tabs:not(:last-child),.pagination:not(:last-child),.message:not(:last-child),.level:not(:last-child),.breadcrumb:not(:last-child),.block:not(:last-child),.title:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.progress:not(:last-child),.notification:not(:last-child),.content:not(:last-child),.box:not(:last-child){margin-bottom:1.5rem}.modal-close,.delete{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:none;position:relative;vertical-align:top;width:20px}.modal-close::before,.delete::before,.modal-close::after,.delete::after{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.modal-close::before,.delete::before{height:2px;width:50%}.modal-close::after,.delete::after{height:50%;width:2px}.modal-close:hover,.delete:hover,.modal-close:focus,.delete:focus{background-color:rgba(10,10,10,0.3)}.modal-close:active,.delete:active{background-color:rgba(10,10,10,0.4)}.is-small.modal-close,#documenter .docs-sidebar form.docs-search>input.modal-close,.is-small.delete,#documenter .docs-sidebar form.docs-search>input.delete{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.modal-close,.is-medium.delete{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.modal-close,.is-large.delete{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.control.is-loading::after,.select.is-loading::after,.loader,.button.is-loading::after{animation:spinAround 500ms infinite linear;border:2px solid #dbdbdb;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.modal-background,.modal,.image.is-square img,#documenter .docs-sidebar .docs-logo>img.is-square img,.image.is-square .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,.image.is-1by1 img,#documenter .docs-sidebar .docs-logo>img.is-1by1 img,.image.is-1by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,.image.is-5by4 img,#documenter .docs-sidebar .docs-logo>img.is-5by4 img,.image.is-5by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,.image.is-4by3 img,#documenter .docs-sidebar .docs-logo>img.is-4by3 img,.image.is-4by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,.image.is-3by2 img,#documenter .docs-sidebar .docs-logo>img.is-3by2 img,.image.is-3by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,.image.is-5by3 img,#documenter .docs-sidebar .docs-logo>img.is-5by3 img,.image.is-5by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,.image.is-16by9 img,#documenter .docs-sidebar .docs-logo>img.is-16by9 img,.image.is-16by9 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,.image.is-2by1 img,#documenter .docs-sidebar .docs-logo>img.is-2by1 img,.image.is-2by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,.image.is-3by1 img,#documenter .docs-sidebar .docs-logo>img.is-3by1 img,.image.is-3by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,.image.is-4by5 img,#documenter .docs-sidebar .docs-logo>img.is-4by5 img,.image.is-4by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,.image.is-3by4 img,#documenter .docs-sidebar .docs-logo>img.is-3by4 img,.image.is-3by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,.image.is-2by3 img,#documenter .docs-sidebar .docs-logo>img.is-2by3 img,.image.is-2by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,.image.is-3by5 img,#documenter .docs-sidebar .docs-logo>img.is-3by5 img,.image.is-3by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,.image.is-9by16 img,#documenter .docs-sidebar .docs-logo>img.is-9by16 img,.image.is-9by16 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,.image.is-1by2 img,#documenter .docs-sidebar .docs-logo>img.is-1by2 img,.image.is-1by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,.image.is-1by3 img,#documenter .docs-sidebar .docs-logo>img.is-1by3 img,.image.is-1by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio,.is-overlay{bottom:0;left:0;position:absolute;right:0;top:0}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}.has-text-white{color:#fff !important}a.has-text-white:hover,a.has-text-white:focus{color:#e6e6e6 !important}.has-background-white{background-color:#fff !important}.has-text-black{color:#0a0a0a !important}a.has-text-black:hover,a.has-text-black:focus{color:#000 !important}.has-background-black{background-color:#0a0a0a !important}.has-text-light{color:#f5f5f5 !important}a.has-text-light:hover,a.has-text-light:focus{color:#dbdbdb !important}.has-background-light{background-color:#f5f5f5 !important}.has-text-dark{color:#363636 !important}a.has-text-dark:hover,a.has-text-dark:focus{color:#1c1c1c !important}.has-background-dark{background-color:#363636 !important}.has-text-primary{color:#4eb5de !important}a.has-text-primary:hover,a.has-text-primary:focus{color:#27a1d2 !important}.has-background-primary{background-color:#4eb5de !important}.has-text-primary-light{color:#eef8fc !important}a.has-text-primary-light:hover,a.has-text-primary-light:focus{color:#c3e6f4 !important}.has-background-primary-light{background-color:#eef8fc !important}.has-text-primary-dark{color:#1a6d8e !important}a.has-text-primary-dark:hover,a.has-text-primary-dark:focus{color:#228eb9 !important}.has-background-primary-dark{background-color:#1a6d8e !important}.has-text-link{color:#2e63b8 !important}a.has-text-link:hover,a.has-text-link:focus{color:#244d8f !important}.has-background-link{background-color:#2e63b8 !important}.has-text-link-light{color:#eff3fb !important}a.has-text-link-light:hover,a.has-text-link-light:focus{color:#c6d6f1 !important}.has-background-link-light{background-color:#eff3fb !important}.has-text-link-dark{color:#3169c4 !important}a.has-text-link-dark:hover,a.has-text-link-dark:focus{color:#5485d4 !important}.has-background-link-dark{background-color:#3169c4 !important}.has-text-info{color:#209cee !important}a.has-text-info:hover,a.has-text-info:focus{color:#1081cb !important}.has-background-info{background-color:#209cee !important}.has-text-info-light{color:#ecf7fe !important}a.has-text-info-light:hover,a.has-text-info-light:focus{color:#bde2fa !important}.has-background-info-light{background-color:#ecf7fe !important}.has-text-info-dark{color:#0e72b4 !important}a.has-text-info-dark:hover,a.has-text-info-dark:focus{color:#1190e3 !important}.has-background-info-dark{background-color:#0e72b4 !important}.has-text-success{color:#22c35b !important}a.has-text-success:hover,a.has-text-success:focus{color:#1a9847 !important}.has-background-success{background-color:#22c35b !important}.has-text-success-light{color:#eefcf3 !important}a.has-text-success-light:hover,a.has-text-success-light:focus{color:#c2f4d4 !important}.has-background-success-light{background-color:#eefcf3 !important}.has-text-success-dark{color:#198f43 !important}a.has-text-success-dark:hover,a.has-text-success-dark:focus{color:#21bb57 !important}.has-background-success-dark{background-color:#198f43 !important}.has-text-warning{color:#ffdd57 !important}a.has-text-warning:hover,a.has-text-warning:focus{color:#ffd324 !important}.has-background-warning{background-color:#ffdd57 !important}.has-text-warning-light{color:#fffbeb !important}a.has-text-warning-light:hover,a.has-text-warning-light:focus{color:#fff1b8 !important}.has-background-warning-light{background-color:#fffbeb !important}.has-text-warning-dark{color:#947600 !important}a.has-text-warning-dark:hover,a.has-text-warning-dark:focus{color:#c79f00 !important}.has-background-warning-dark{background-color:#947600 !important}.has-text-danger{color:#da0b00 !important}a.has-text-danger:hover,a.has-text-danger:focus{color:#a70800 !important}.has-background-danger{background-color:#da0b00 !important}.has-text-danger-light{color:#ffeceb !important}a.has-text-danger-light:hover,a.has-text-danger-light:focus{color:#ffbbb8 !important}.has-background-danger-light{background-color:#ffeceb !important}.has-text-danger-dark{color:#f50c00 !important}a.has-text-danger-dark:hover,a.has-text-danger-dark:focus{color:#ff3429 !important}.has-background-danger-dark{background-color:#f50c00 !important}.has-text-black-bis{color:#121212 !important}.has-background-black-bis{background-color:#121212 !important}.has-text-black-ter{color:#242424 !important}.has-background-black-ter{background-color:#242424 !important}.has-text-grey-darker{color:#363636 !important}.has-background-grey-darker{background-color:#363636 !important}.has-text-grey-dark{color:#4a4a4a !important}.has-background-grey-dark{background-color:#4a4a4a !important}.has-text-grey{color:#6b6b6b !important}.has-background-grey{background-color:#6b6b6b !important}.has-text-grey-light{color:#b5b5b5 !important}.has-background-grey-light{background-color:#b5b5b5 !important}.has-text-grey-lighter{color:#dbdbdb !important}.has-background-grey-lighter{background-color:#dbdbdb !important}.has-text-white-ter{color:#f5f5f5 !important}.has-background-white-ter{background-color:#f5f5f5 !important}.has-text-white-bis{color:#fafafa !important}.has-background-white-bis{background-color:#fafafa !important}.is-flex-direction-row{flex-direction:row !important}.is-flex-direction-row-reverse{flex-direction:row-reverse !important}.is-flex-direction-column{flex-direction:column !important}.is-flex-direction-column-reverse{flex-direction:column-reverse !important}.is-flex-wrap-nowrap{flex-wrap:nowrap !important}.is-flex-wrap-wrap{flex-wrap:wrap !important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse !important}.is-justify-content-flex-start{justify-content:flex-start !important}.is-justify-content-flex-end{justify-content:flex-end !important}.is-justify-content-center{justify-content:center !important}.is-justify-content-space-between{justify-content:space-between !important}.is-justify-content-space-around{justify-content:space-around !important}.is-justify-content-space-evenly{justify-content:space-evenly !important}.is-justify-content-start{justify-content:start !important}.is-justify-content-end{justify-content:end !important}.is-justify-content-left{justify-content:left !important}.is-justify-content-right{justify-content:right !important}.is-align-content-flex-start{align-content:flex-start !important}.is-align-content-flex-end{align-content:flex-end !important}.is-align-content-center{align-content:center !important}.is-align-content-space-between{align-content:space-between !important}.is-align-content-space-around{align-content:space-around !important}.is-align-content-space-evenly{align-content:space-evenly !important}.is-align-content-stretch{align-content:stretch !important}.is-align-content-start{align-content:start !important}.is-align-content-end{align-content:end !important}.is-align-content-baseline{align-content:baseline !important}.is-align-items-stretch{align-items:stretch !important}.is-align-items-flex-start{align-items:flex-start !important}.is-align-items-flex-end{align-items:flex-end !important}.is-align-items-center{align-items:center !important}.is-align-items-baseline{align-items:baseline !important}.is-align-items-start{align-items:start !important}.is-align-items-end{align-items:end !important}.is-align-items-self-start{align-items:self-start !important}.is-align-items-self-end{align-items:self-end !important}.is-align-self-auto{align-self:auto !important}.is-align-self-flex-start{align-self:flex-start !important}.is-align-self-flex-end{align-self:flex-end !important}.is-align-self-center{align-self:center !important}.is-align-self-baseline{align-self:baseline !important}.is-align-self-stretch{align-self:stretch !important}.is-flex-grow-0{flex-grow:0 !important}.is-flex-grow-1{flex-grow:1 !important}.is-flex-grow-2{flex-grow:2 !important}.is-flex-grow-3{flex-grow:3 !important}.is-flex-grow-4{flex-grow:4 !important}.is-flex-grow-5{flex-grow:5 !important}.is-flex-shrink-0{flex-shrink:0 !important}.is-flex-shrink-1{flex-shrink:1 !important}.is-flex-shrink-2{flex-shrink:2 !important}.is-flex-shrink-3{flex-shrink:3 !important}.is-flex-shrink-4{flex-shrink:4 !important}.is-flex-shrink-5{flex-shrink:5 !important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-clickable{cursor:pointer !important;pointer-events:all !important}.is-clipped{overflow:hidden !important}.is-relative{position:relative !important}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.m-0{margin:0 !important}.mt-0{margin-top:0 !important}.mr-0{margin-right:0 !important}.mb-0{margin-bottom:0 !important}.ml-0{margin-left:0 !important}.mx-0{margin-left:0 !important;margin-right:0 !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.m-1{margin:.25rem !important}.mt-1{margin-top:.25rem !important}.mr-1{margin-right:.25rem !important}.mb-1{margin-bottom:.25rem !important}.ml-1{margin-left:.25rem !important}.mx-1{margin-left:.25rem !important;margin-right:.25rem !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.m-2{margin:.5rem !important}.mt-2{margin-top:.5rem !important}.mr-2{margin-right:.5rem !important}.mb-2{margin-bottom:.5rem !important}.ml-2{margin-left:.5rem !important}.mx-2{margin-left:.5rem !important;margin-right:.5rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.m-3{margin:.75rem !important}.mt-3{margin-top:.75rem !important}.mr-3{margin-right:.75rem !important}.mb-3{margin-bottom:.75rem !important}.ml-3{margin-left:.75rem !important}.mx-3{margin-left:.75rem !important;margin-right:.75rem !important}.my-3{margin-top:.75rem !important;margin-bottom:.75rem !important}.m-4{margin:1rem !important}.mt-4{margin-top:1rem !important}.mr-4{margin-right:1rem !important}.mb-4{margin-bottom:1rem !important}.ml-4{margin-left:1rem !important}.mx-4{margin-left:1rem !important;margin-right:1rem !important}.my-4{margin-top:1rem !important;margin-bottom:1rem !important}.m-5{margin:1.5rem !important}.mt-5{margin-top:1.5rem !important}.mr-5{margin-right:1.5rem !important}.mb-5{margin-bottom:1.5rem !important}.ml-5{margin-left:1.5rem !important}.mx-5{margin-left:1.5rem !important;margin-right:1.5rem !important}.my-5{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.m-6{margin:3rem !important}.mt-6{margin-top:3rem !important}.mr-6{margin-right:3rem !important}.mb-6{margin-bottom:3rem !important}.ml-6{margin-left:3rem !important}.mx-6{margin-left:3rem !important;margin-right:3rem !important}.my-6{margin-top:3rem !important;margin-bottom:3rem !important}.m-auto{margin:auto !important}.mt-auto{margin-top:auto !important}.mr-auto{margin-right:auto !important}.mb-auto{margin-bottom:auto !important}.ml-auto{margin-left:auto !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.p-0{padding:0 !important}.pt-0{padding-top:0 !important}.pr-0{padding-right:0 !important}.pb-0{padding-bottom:0 !important}.pl-0{padding-left:0 !important}.px-0{padding-left:0 !important;padding-right:0 !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.p-1{padding:.25rem !important}.pt-1{padding-top:.25rem !important}.pr-1{padding-right:.25rem !important}.pb-1{padding-bottom:.25rem !important}.pl-1{padding-left:.25rem !important}.px-1{padding-left:.25rem !important;padding-right:.25rem !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.p-2{padding:.5rem !important}.pt-2{padding-top:.5rem !important}.pr-2{padding-right:.5rem !important}.pb-2{padding-bottom:.5rem !important}.pl-2{padding-left:.5rem !important}.px-2{padding-left:.5rem !important;padding-right:.5rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.p-3{padding:.75rem !important}.pt-3{padding-top:.75rem !important}.pr-3{padding-right:.75rem !important}.pb-3{padding-bottom:.75rem !important}.pl-3{padding-left:.75rem !important}.px-3{padding-left:.75rem !important;padding-right:.75rem !important}.py-3{padding-top:.75rem !important;padding-bottom:.75rem !important}.p-4{padding:1rem !important}.pt-4{padding-top:1rem !important}.pr-4{padding-right:1rem !important}.pb-4{padding-bottom:1rem !important}.pl-4{padding-left:1rem !important}.px-4{padding-left:1rem !important;padding-right:1rem !important}.py-4{padding-top:1rem !important;padding-bottom:1rem !important}.p-5{padding:1.5rem !important}.pt-5{padding-top:1.5rem !important}.pr-5{padding-right:1.5rem !important}.pb-5{padding-bottom:1.5rem !important}.pl-5{padding-left:1.5rem !important}.px-5{padding-left:1.5rem !important;padding-right:1.5rem !important}.py-5{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.p-6{padding:3rem !important}.pt-6{padding-top:3rem !important}.pr-6{padding-right:3rem !important}.pb-6{padding-bottom:3rem !important}.pl-6{padding-left:3rem !important}.px-6{padding-left:3rem !important;padding-right:3rem !important}.py-6{padding-top:3rem !important;padding-bottom:3rem !important}.p-auto{padding:auto !important}.pt-auto{padding-top:auto !important}.pr-auto{padding-right:auto !important}.pb-auto{padding-bottom:auto !important}.pl-auto{padding-left:auto !important}.px-auto{padding-left:auto !important;padding-right:auto !important}.py-auto{padding-top:auto !important;padding-bottom:auto !important}.is-size-1{font-size:3rem !important}.is-size-2{font-size:2.5rem !important}.is-size-3{font-size:2rem !important}.is-size-4{font-size:1.5rem !important}.is-size-5{font-size:1.25rem !important}.is-size-6{font-size:1rem !important}.is-size-7,.docstring>section>a.docs-sourcelink{font-size:.75rem !important}@media screen and (max-width: 768px){.is-size-1-mobile{font-size:3rem !important}.is-size-2-mobile{font-size:2.5rem !important}.is-size-3-mobile{font-size:2rem !important}.is-size-4-mobile{font-size:1.5rem !important}.is-size-5-mobile{font-size:1.25rem !important}.is-size-6-mobile{font-size:1rem !important}.is-size-7-mobile{font-size:.75rem !important}}@media screen and (min-width: 769px),print{.is-size-1-tablet{font-size:3rem !important}.is-size-2-tablet{font-size:2.5rem !important}.is-size-3-tablet{font-size:2rem !important}.is-size-4-tablet{font-size:1.5rem !important}.is-size-5-tablet{font-size:1.25rem !important}.is-size-6-tablet{font-size:1rem !important}.is-size-7-tablet{font-size:.75rem !important}}@media screen and (max-width: 1055px){.is-size-1-touch{font-size:3rem !important}.is-size-2-touch{font-size:2.5rem !important}.is-size-3-touch{font-size:2rem !important}.is-size-4-touch{font-size:1.5rem !important}.is-size-5-touch{font-size:1.25rem !important}.is-size-6-touch{font-size:1rem !important}.is-size-7-touch{font-size:.75rem !important}}@media screen and (min-width: 1056px){.is-size-1-desktop{font-size:3rem !important}.is-size-2-desktop{font-size:2.5rem !important}.is-size-3-desktop{font-size:2rem !important}.is-size-4-desktop{font-size:1.5rem !important}.is-size-5-desktop{font-size:1.25rem !important}.is-size-6-desktop{font-size:1rem !important}.is-size-7-desktop{font-size:.75rem !important}}@media screen and (min-width: 1216px){.is-size-1-widescreen{font-size:3rem !important}.is-size-2-widescreen{font-size:2.5rem !important}.is-size-3-widescreen{font-size:2rem !important}.is-size-4-widescreen{font-size:1.5rem !important}.is-size-5-widescreen{font-size:1.25rem !important}.is-size-6-widescreen{font-size:1rem !important}.is-size-7-widescreen{font-size:.75rem !important}}@media screen and (min-width: 1408px){.is-size-1-fullhd{font-size:3rem !important}.is-size-2-fullhd{font-size:2.5rem !important}.is-size-3-fullhd{font-size:2rem !important}.is-size-4-fullhd{font-size:1.5rem !important}.is-size-5-fullhd{font-size:1.25rem !important}.is-size-6-fullhd{font-size:1rem !important}.is-size-7-fullhd{font-size:.75rem !important}}.has-text-centered{text-align:center !important}.has-text-justified{text-align:justify !important}.has-text-left{text-align:left !important}.has-text-right{text-align:right !important}@media screen and (max-width: 768px){.has-text-centered-mobile{text-align:center !important}}@media screen and (min-width: 769px),print{.has-text-centered-tablet{text-align:center !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-centered-tablet-only{text-align:center !important}}@media screen and (max-width: 1055px){.has-text-centered-touch{text-align:center !important}}@media screen and (min-width: 1056px){.has-text-centered-desktop{text-align:center !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-centered-desktop-only{text-align:center !important}}@media screen and (min-width: 1216px){.has-text-centered-widescreen{text-align:center !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-centered-widescreen-only{text-align:center !important}}@media screen and (min-width: 1408px){.has-text-centered-fullhd{text-align:center !important}}@media screen and (max-width: 768px){.has-text-justified-mobile{text-align:justify !important}}@media screen and (min-width: 769px),print{.has-text-justified-tablet{text-align:justify !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-justified-tablet-only{text-align:justify !important}}@media screen and (max-width: 1055px){.has-text-justified-touch{text-align:justify !important}}@media screen and (min-width: 1056px){.has-text-justified-desktop{text-align:justify !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-justified-desktop-only{text-align:justify !important}}@media screen and (min-width: 1216px){.has-text-justified-widescreen{text-align:justify !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-justified-widescreen-only{text-align:justify !important}}@media screen and (min-width: 1408px){.has-text-justified-fullhd{text-align:justify !important}}@media screen and (max-width: 768px){.has-text-left-mobile{text-align:left !important}}@media screen and (min-width: 769px),print{.has-text-left-tablet{text-align:left !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-left-tablet-only{text-align:left !important}}@media screen and (max-width: 1055px){.has-text-left-touch{text-align:left !important}}@media screen and (min-width: 1056px){.has-text-left-desktop{text-align:left !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-left-desktop-only{text-align:left !important}}@media screen and (min-width: 1216px){.has-text-left-widescreen{text-align:left !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-left-widescreen-only{text-align:left !important}}@media screen and (min-width: 1408px){.has-text-left-fullhd{text-align:left !important}}@media screen and (max-width: 768px){.has-text-right-mobile{text-align:right !important}}@media screen and (min-width: 769px),print{.has-text-right-tablet{text-align:right !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-right-tablet-only{text-align:right !important}}@media screen and (max-width: 1055px){.has-text-right-touch{text-align:right !important}}@media screen and (min-width: 1056px){.has-text-right-desktop{text-align:right !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-right-desktop-only{text-align:right !important}}@media screen and (min-width: 1216px){.has-text-right-widescreen{text-align:right !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-right-widescreen-only{text-align:right !important}}@media screen and (min-width: 1408px){.has-text-right-fullhd{text-align:right !important}}.is-capitalized{text-transform:capitalize !important}.is-lowercase{text-transform:lowercase !important}.is-uppercase{text-transform:uppercase !important}.is-italic{font-style:italic !important}.is-underlined{text-decoration:underline !important}.has-text-weight-light{font-weight:300 !important}.has-text-weight-normal{font-weight:400 !important}.has-text-weight-medium{font-weight:500 !important}.has-text-weight-semibold{font-weight:600 !important}.has-text-weight-bold{font-weight:700 !important}.is-family-primary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-secondary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-sans-serif{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-monospace{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-family-code{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-block{display:block !important}@media screen and (max-width: 768px){.is-block-mobile{display:block !important}}@media screen and (min-width: 769px),print{.is-block-tablet{display:block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-block-tablet-only{display:block !important}}@media screen and (max-width: 1055px){.is-block-touch{display:block !important}}@media screen and (min-width: 1056px){.is-block-desktop{display:block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-block-desktop-only{display:block !important}}@media screen and (min-width: 1216px){.is-block-widescreen{display:block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-block-widescreen-only{display:block !important}}@media screen and (min-width: 1408px){.is-block-fullhd{display:block !important}}.is-flex{display:flex !important}@media screen and (max-width: 768px){.is-flex-mobile{display:flex !important}}@media screen and (min-width: 769px),print{.is-flex-tablet{display:flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-flex-tablet-only{display:flex !important}}@media screen and (max-width: 1055px){.is-flex-touch{display:flex !important}}@media screen and (min-width: 1056px){.is-flex-desktop{display:flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-flex-desktop-only{display:flex !important}}@media screen and (min-width: 1216px){.is-flex-widescreen{display:flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-flex-widescreen-only{display:flex !important}}@media screen and (min-width: 1408px){.is-flex-fullhd{display:flex !important}}.is-inline{display:inline !important}@media screen and (max-width: 768px){.is-inline-mobile{display:inline !important}}@media screen and (min-width: 769px),print{.is-inline-tablet{display:inline !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-tablet-only{display:inline !important}}@media screen and (max-width: 1055px){.is-inline-touch{display:inline !important}}@media screen and (min-width: 1056px){.is-inline-desktop{display:inline !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-desktop-only{display:inline !important}}@media screen and (min-width: 1216px){.is-inline-widescreen{display:inline !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-widescreen-only{display:inline !important}}@media screen and (min-width: 1408px){.is-inline-fullhd{display:inline !important}}.is-inline-block{display:inline-block !important}@media screen and (max-width: 768px){.is-inline-block-mobile{display:inline-block !important}}@media screen and (min-width: 769px),print{.is-inline-block-tablet{display:inline-block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-block-tablet-only{display:inline-block !important}}@media screen and (max-width: 1055px){.is-inline-block-touch{display:inline-block !important}}@media screen and (min-width: 1056px){.is-inline-block-desktop{display:inline-block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-block-desktop-only{display:inline-block !important}}@media screen and (min-width: 1216px){.is-inline-block-widescreen{display:inline-block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-block-widescreen-only{display:inline-block !important}}@media screen and (min-width: 1408px){.is-inline-block-fullhd{display:inline-block !important}}.is-inline-flex{display:inline-flex !important}@media screen and (max-width: 768px){.is-inline-flex-mobile{display:inline-flex !important}}@media screen and (min-width: 769px),print{.is-inline-flex-tablet{display:inline-flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-flex-tablet-only{display:inline-flex !important}}@media screen and (max-width: 1055px){.is-inline-flex-touch{display:inline-flex !important}}@media screen and (min-width: 1056px){.is-inline-flex-desktop{display:inline-flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-flex-desktop-only{display:inline-flex !important}}@media screen and (min-width: 1216px){.is-inline-flex-widescreen{display:inline-flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-flex-widescreen-only{display:inline-flex !important}}@media screen and (min-width: 1408px){.is-inline-flex-fullhd{display:inline-flex !important}}.is-hidden{display:none !important}.is-sr-only{border:none !important;clip:rect(0, 0, 0, 0) !important;height:0.01em !important;overflow:hidden !important;padding:0 !important;position:absolute !important;white-space:nowrap !important;width:0.01em !important}@media screen and (max-width: 768px){.is-hidden-mobile{display:none !important}}@media screen and (min-width: 769px),print{.is-hidden-tablet{display:none !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-hidden-tablet-only{display:none !important}}@media screen and (max-width: 1055px){.is-hidden-touch{display:none !important}}@media screen and (min-width: 1056px){.is-hidden-desktop{display:none !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-hidden-desktop-only{display:none !important}}@media screen and (min-width: 1216px){.is-hidden-widescreen{display:none !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-hidden-widescreen-only{display:none !important}}@media screen and (min-width: 1408px){.is-hidden-fullhd{display:none !important}}.is-invisible{visibility:hidden !important}@media screen and (max-width: 768px){.is-invisible-mobile{visibility:hidden !important}}@media screen and (min-width: 769px),print{.is-invisible-tablet{visibility:hidden !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-invisible-tablet-only{visibility:hidden !important}}@media screen and (max-width: 1055px){.is-invisible-touch{visibility:hidden !important}}@media screen and (min-width: 1056px){.is-invisible-desktop{visibility:hidden !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-invisible-desktop-only{visibility:hidden !important}}@media screen and (min-width: 1216px){.is-invisible-widescreen{visibility:hidden !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-invisible-widescreen-only{visibility:hidden !important}}@media screen and (min-width: 1408px){.is-invisible-fullhd{visibility:hidden !important}}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}body{color:#222;font-size:1em;font-weight:400;line-height:1.5}a{color:#2e63b8;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:rgba(0,0,0,0.05);color:#000;font-size:.875em;font-weight:normal;padding:.1em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type="checkbox"],input[type="radio"]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#222;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#222;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:#222}@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:#bbb;color:#222;display:block;padding:1.25rem}a.box:hover,a.box:focus{box-shadow:0 0.5em 1em -0.125em rgba(10,10,10,0.1),0 0 0 1px #2e63b8}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #2e63b8}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#222;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-small,.button #documenter .docs-sidebar form.docs-search>input.icon,#documenter .docs-sidebar .button form.docs-search>input.icon,.button .icon.is-medium,.button .icon.is-large{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-0.5em - 1px);margin-right:.25em}.button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 1px)}.button:hover,.button.is-hovered{border-color:#b5b5b5;color:#363636}.button:focus,.button.is-focused{border-color:#3c5dcd;color:#363636}.button:focus:not(:active),.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.button:active,.button.is-active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#222;text-decoration:underline}.button.is-text:hover,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text.is-focused{background-color:#f5f5f5;color:#222}.button.is-text:active,.button.is-text.is-active{background-color:#e8e8e8;color:#222}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-ghost{background:none;border-color:rgba(0,0,0,0);color:#2e63b8;text-decoration:none}.button.is-ghost:hover,.button.is-ghost.is-hovered{color:#2e63b8;text-decoration:underline}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white:hover,.button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white:focus,.button.is-white.is-focused{border-color:transparent;color:#0a0a0a}.button.is-white:focus:not(:active),.button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.button.is-white:active,.button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted:hover,.button.is-white.is-inverted.is-hovered{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined:hover,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-white.is-outlined.is-loading:hover::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined:hover,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading:hover::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black:hover,.button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}.button.is-black:focus,.button.is-black.is-focused{border-color:transparent;color:#fff}.button.is-black:focus:not(:active),.button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.button.is-black:active,.button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted:hover,.button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined:hover,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-black.is-outlined.is-loading:hover::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined:hover,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading:hover::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:hover,.button.is-light.is-hovered{background-color:#eee;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:focus,.button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:focus:not(:active),.button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.button.is-light:active,.button.is-light.is-active{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#f5f5f5}.button.is-light.is-inverted:hover,.button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined:hover,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined.is-focused{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,0.7)}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-light.is-outlined.is-loading:hover::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}.button.is-light.is-inverted.is-outlined:hover,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading:hover::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}.button.is-dark,.content kbd.button{background-color:#363636;border-color:transparent;color:#fff}.button.is-dark:hover,.content kbd.button:hover,.button.is-dark.is-hovered,.content kbd.button.is-hovered{background-color:#2f2f2f;border-color:transparent;color:#fff}.button.is-dark:focus,.content kbd.button:focus,.button.is-dark.is-focused,.content kbd.button.is-focused{border-color:transparent;color:#fff}.button.is-dark:focus:not(:active),.content kbd.button:focus:not(:active),.button.is-dark.is-focused:not(:active),.content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.button.is-dark:active,.content kbd.button:active,.button.is-dark.is-active,.content kbd.button.is-active{background-color:#292929;border-color:transparent;color:#fff}.button.is-dark[disabled],.content kbd.button[disabled],fieldset[disabled] .button.is-dark,fieldset[disabled] .content kbd.button,.content fieldset[disabled] kbd.button{background-color:#363636;border-color:#363636;box-shadow:none}.button.is-dark.is-inverted,.content kbd.button.is-inverted{background-color:#fff;color:#363636}.button.is-dark.is-inverted:hover,.content kbd.button.is-inverted:hover,.button.is-dark.is-inverted.is-hovered,.content kbd.button.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-dark.is-inverted[disabled],.content kbd.button.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted,fieldset[disabled] .content kbd.button.is-inverted,.content fieldset[disabled] kbd.button.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after,.content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-dark.is-outlined,.content kbd.button.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined:hover,.content kbd.button.is-outlined:hover,.button.is-dark.is-outlined.is-hovered,.content kbd.button.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.content kbd.button.is-outlined:focus,.button.is-dark.is-outlined.is-focused,.content kbd.button.is-outlined.is-focused{background-color:#363636;border-color:#363636;color:#fff}.button.is-dark.is-outlined.is-loading::after,.content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636 !important}.button.is-dark.is-outlined.is-loading:hover::after,.content kbd.button.is-outlined.is-loading:hover::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.content kbd.button.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.content kbd.button.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading.is-focused::after,.content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-dark.is-outlined[disabled],.content kbd.button.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined,fieldset[disabled] .content kbd.button.is-outlined,.content fieldset[disabled] kbd.button.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined,.content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-dark.is-inverted.is-outlined:hover,.content kbd.button.is-inverted.is-outlined:hover,.button.is-dark.is-inverted.is-outlined.is-hovered,.content kbd.button.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.content kbd.button.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined.is-focused,.content kbd.button.is-inverted.is-outlined.is-focused{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading:hover::after,.content kbd.button.is-inverted.is-outlined.is-loading:hover::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.content kbd.button.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #363636 #363636 !important}.button.is-dark.is-inverted.is-outlined[disabled],.content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined,fieldset[disabled] .content kbd.button.is-inverted.is-outlined,.content fieldset[disabled] kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary,.docstring>section>a.button.docs-sourcelink{background-color:#4eb5de;border-color:transparent;color:#fff}.button.is-primary:hover,.docstring>section>a.button.docs-sourcelink:hover,.button.is-primary.is-hovered,.docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#43b1dc;border-color:transparent;color:#fff}.button.is-primary:focus,.docstring>section>a.button.docs-sourcelink:focus,.button.is-primary.is-focused,.docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}.button.is-primary:focus:not(:active),.docstring>section>a.button.docs-sourcelink:focus:not(:active),.button.is-primary.is-focused:not(:active),.docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.button.is-primary:active,.docstring>section>a.button.docs-sourcelink:active,.button.is-primary.is-active,.docstring>section>a.button.is-active.docs-sourcelink{background-color:#39acda;border-color:transparent;color:#fff}.button.is-primary[disabled],.docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary,fieldset[disabled] .docstring>section>a.button.docs-sourcelink{background-color:#4eb5de;border-color:#4eb5de;box-shadow:none}.button.is-primary.is-inverted,.docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#4eb5de}.button.is-primary.is-inverted:hover,.docstring>section>a.button.is-inverted.docs-sourcelink:hover,.button.is-primary.is-inverted.is-hovered,.docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],.docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-inverted,fieldset[disabled] .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#4eb5de}.button.is-primary.is-loading::after,.docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}.button.is-primary.is-outlined,.docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#4eb5de;color:#4eb5de}.button.is-primary.is-outlined:hover,.docstring>section>a.button.is-outlined.docs-sourcelink:hover,.button.is-primary.is-outlined.is-hovered,.docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,.button.is-primary.is-outlined:focus,.docstring>section>a.button.is-outlined.docs-sourcelink:focus,.button.is-primary.is-outlined.is-focused,.docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#4eb5de;border-color:#4eb5de;color:#fff}.button.is-primary.is-outlined.is-loading::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #4eb5de #4eb5de !important}.button.is-primary.is-outlined.is-loading:hover::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,.button.is-primary.is-outlined.is-loading:focus::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,.button.is-primary.is-outlined.is-loading.is-focused::after,.docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}.button.is-primary.is-outlined[disabled],.docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-outlined,fieldset[disabled] .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#4eb5de;box-shadow:none;color:#4eb5de}.button.is-primary.is-inverted.is-outlined,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined:hover,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,.button.is-primary.is-inverted.is-outlined.is-hovered,.docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,.button.is-primary.is-inverted.is-outlined:focus,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,.button.is-primary.is-inverted.is-outlined.is-focused,.docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#4eb5de}.button.is-primary.is-inverted.is-outlined.is-loading:hover::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #4eb5de #4eb5de !important}.button.is-primary.is-inverted.is-outlined[disabled],.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined,fieldset[disabled] .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary.is-light,.docstring>section>a.button.is-light.docs-sourcelink{background-color:#eef8fc;color:#1a6d8e}.button.is-primary.is-light:hover,.docstring>section>a.button.is-light.docs-sourcelink:hover,.button.is-primary.is-light.is-hovered,.docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e3f3fa;border-color:transparent;color:#1a6d8e}.button.is-primary.is-light:active,.docstring>section>a.button.is-light.docs-sourcelink:active,.button.is-primary.is-light.is-active,.docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#d8eff8;border-color:transparent;color:#1a6d8e}.button.is-link{background-color:#2e63b8;border-color:transparent;color:#fff}.button.is-link:hover,.button.is-link.is-hovered{background-color:#2b5eae;border-color:transparent;color:#fff}.button.is-link:focus,.button.is-link.is-focused{border-color:transparent;color:#fff}.button.is-link:focus:not(:active),.button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.button.is-link:active,.button.is-link.is-active{background-color:#2958a4;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#2e63b8;border-color:#2e63b8;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#2e63b8}.button.is-link.is-inverted:hover,.button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#2e63b8}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-link.is-outlined{background-color:transparent;border-color:#2e63b8;color:#2e63b8}.button.is-link.is-outlined:hover,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined.is-focused{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #2e63b8 #2e63b8 !important}.button.is-link.is-outlined.is-loading:hover::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#2e63b8;box-shadow:none;color:#2e63b8}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined:hover,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#2e63b8}.button.is-link.is-inverted.is-outlined.is-loading:hover::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #2e63b8 #2e63b8 !important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link.is-light{background-color:#eff3fb;color:#3169c4}.button.is-link.is-light:hover,.button.is-link.is-light.is-hovered{background-color:#e4ecf8;border-color:transparent;color:#3169c4}.button.is-link.is-light:active,.button.is-link.is-light.is-active{background-color:#dae5f6;border-color:transparent;color:#3169c4}.button.is-info{background-color:#209cee;border-color:transparent;color:#fff}.button.is-info:hover,.button.is-info.is-hovered{background-color:#1497ed;border-color:transparent;color:#fff}.button.is-info:focus,.button.is-info.is-focused{border-color:transparent;color:#fff}.button.is-info:focus:not(:active),.button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.button.is-info:active,.button.is-info.is-active{background-color:#1190e3;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#209cee;border-color:#209cee;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#209cee}.button.is-info.is-inverted:hover,.button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#209cee}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-info.is-outlined{background-color:transparent;border-color:#209cee;color:#209cee}.button.is-info.is-outlined:hover,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined.is-focused{background-color:#209cee;border-color:#209cee;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #209cee #209cee !important}.button.is-info.is-outlined.is-loading:hover::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#209cee;box-shadow:none;color:#209cee}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined:hover,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#209cee}.button.is-info.is-inverted.is-outlined.is-loading:hover::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #209cee #209cee !important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info.is-light{background-color:#ecf7fe;color:#0e72b4}.button.is-info.is-light:hover,.button.is-info.is-light.is-hovered{background-color:#e0f1fd;border-color:transparent;color:#0e72b4}.button.is-info.is-light:active,.button.is-info.is-light.is-active{background-color:#d4ecfc;border-color:transparent;color:#0e72b4}.button.is-success{background-color:#22c35b;border-color:transparent;color:#fff}.button.is-success:hover,.button.is-success.is-hovered{background-color:#20b856;border-color:transparent;color:#fff}.button.is-success:focus,.button.is-success.is-focused{border-color:transparent;color:#fff}.button.is-success:focus:not(:active),.button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.button.is-success:active,.button.is-success.is-active{background-color:#1ead51;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#22c35b;border-color:#22c35b;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#22c35b}.button.is-success.is-inverted:hover,.button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#22c35b}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-success.is-outlined{background-color:transparent;border-color:#22c35b;color:#22c35b}.button.is-success.is-outlined:hover,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined.is-focused{background-color:#22c35b;border-color:#22c35b;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #22c35b #22c35b !important}.button.is-success.is-outlined.is-loading:hover::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#22c35b;box-shadow:none;color:#22c35b}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined:hover,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#22c35b}.button.is-success.is-inverted.is-outlined.is-loading:hover::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #22c35b #22c35b !important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success.is-light{background-color:#eefcf3;color:#198f43}.button.is-success.is-light:hover,.button.is-success.is-light.is-hovered{background-color:#e3faeb;border-color:transparent;color:#198f43}.button.is-success.is-light:active,.button.is-success.is-light.is-active{background-color:#d8f8e3;border-color:transparent;color:#198f43}.button.is-warning{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:hover,.button.is-warning.is-hovered{background-color:#ffda4a;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:focus,.button.is-warning.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:focus:not(:active),.button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.button.is-warning:active,.button.is-warning.is-active{background-color:#ffd83e;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffdd57;border-color:#ffdd57;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,0.7);color:#ffdd57}.button.is-warning.is-inverted:hover,.button.is-warning.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ffdd57}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;color:#ffdd57}.button.is-warning.is-outlined:hover,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined.is-focused{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffdd57 #ffdd57 !important}.button.is-warning.is-outlined.is-loading:hover::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;box-shadow:none;color:#ffdd57}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}.button.is-warning.is-inverted.is-outlined:hover,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ffdd57}.button.is-warning.is-inverted.is-outlined.is-loading:hover::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ffdd57 #ffdd57 !important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}.button.is-warning.is-light{background-color:#fffbeb;color:#947600}.button.is-warning.is-light:hover,.button.is-warning.is-light.is-hovered{background-color:#fff8de;border-color:transparent;color:#947600}.button.is-warning.is-light:active,.button.is-warning.is-light.is-active{background-color:#fff6d1;border-color:transparent;color:#947600}.button.is-danger{background-color:#da0b00;border-color:transparent;color:#fff}.button.is-danger:hover,.button.is-danger.is-hovered{background-color:#cd0a00;border-color:transparent;color:#fff}.button.is-danger:focus,.button.is-danger.is-focused{border-color:transparent;color:#fff}.button.is-danger:focus:not(:active),.button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.button.is-danger:active,.button.is-danger.is-active{background-color:#c10a00;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#da0b00;border-color:#da0b00;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#da0b00}.button.is-danger.is-inverted:hover,.button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#da0b00}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-danger.is-outlined{background-color:transparent;border-color:#da0b00;color:#da0b00}.button.is-danger.is-outlined:hover,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined.is-focused{background-color:#da0b00;border-color:#da0b00;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #da0b00 #da0b00 !important}.button.is-danger.is-outlined.is-loading:hover::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#da0b00;box-shadow:none;color:#da0b00}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined:hover,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#da0b00}.button.is-danger.is-inverted.is-outlined.is-loading:hover::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #da0b00 #da0b00 !important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-danger.is-light{background-color:#ffeceb;color:#f50c00}.button.is-danger.is-light:hover,.button.is-danger.is-light.is-hovered{background-color:#ffe0de;border-color:transparent;color:#f50c00}.button.is-danger.is-light:active,.button.is-danger.is-light.is-active{background-color:#ffd3d1;border-color:transparent;color:#f50c00}.button.is-small,#documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}.button.is-small:not(.is-rounded),#documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:2px}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent !important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em * 0.5));top:calc(50% - (1em * 0.5));position:absolute !important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#6b6b6b;box-shadow:none;pointer-events:none}.button.is-rounded,#documenter .docs-sidebar form.docs-search>input.button{border-radius:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:0.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}.buttons:last-child{margin-bottom:-0.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button:hover,.buttons.has-addons .button.is-hovered{z-index:2}.buttons.has-addons .button:focus,.buttons.has-addons .button.is-focused,.buttons.has-addons .button:active,.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-selected{z-index:3}.buttons.has-addons .button:focus:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-selected:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}@media screen and (max-width: 768px){.button.is-responsive.is-small,#documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.65625rem}.button.is-responsive.is-medium{font-size:.75rem}.button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.button.is-responsive.is-small,#documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.75rem}.button.is-responsive.is-medium{font-size:1rem}.button.is-responsive.is-large{font-size:1.25rem}}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){.container{max-width:992px}}@media screen and (max-width: 1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}.content li+li{margin-top:0.25em}.content p:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content ul:not(:last-child),.content blockquote:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#222;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:0.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:0.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:0.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:0.8em}.content h5{font-size:1.125em;margin-bottom:0.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}.content ol.is-lower-roman:not([type]){list-style-type:lower-roman}.content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}.content ol.is-upper-roman:not([type]){list-style-type:upper-roman}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:0.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}.content sup,.content sub{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.content table th{color:#222}.content table th:not([align]){text-align:inherit}.content table thead td,.content table thead th{border-width:0 0 2px;color:#222}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#222}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small,#documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}.content.is-normal{font-size:1rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small,#documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-right:.25em}.icon-text .icon:not(:first-child){margin-left:.25em}div.icon-text{display:flex}.image,#documenter .docs-sidebar .docs-logo>img{display:block;position:relative}.image img,#documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}.image img.is-rounded,#documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:9999px}.image.is-fullwidth,#documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}.image.is-square img,#documenter .docs-sidebar .docs-logo>img.is-square img,.image.is-square .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,.image.is-1by1 img,#documenter .docs-sidebar .docs-logo>img.is-1by1 img,.image.is-1by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,.image.is-5by4 img,#documenter .docs-sidebar .docs-logo>img.is-5by4 img,.image.is-5by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,.image.is-4by3 img,#documenter .docs-sidebar .docs-logo>img.is-4by3 img,.image.is-4by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,.image.is-3by2 img,#documenter .docs-sidebar .docs-logo>img.is-3by2 img,.image.is-3by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,.image.is-5by3 img,#documenter .docs-sidebar .docs-logo>img.is-5by3 img,.image.is-5by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,.image.is-16by9 img,#documenter .docs-sidebar .docs-logo>img.is-16by9 img,.image.is-16by9 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,.image.is-2by1 img,#documenter .docs-sidebar .docs-logo>img.is-2by1 img,.image.is-2by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,.image.is-3by1 img,#documenter .docs-sidebar .docs-logo>img.is-3by1 img,.image.is-3by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,.image.is-4by5 img,#documenter .docs-sidebar .docs-logo>img.is-4by5 img,.image.is-4by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,.image.is-3by4 img,#documenter .docs-sidebar .docs-logo>img.is-3by4 img,.image.is-3by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,.image.is-2by3 img,#documenter .docs-sidebar .docs-logo>img.is-2by3 img,.image.is-2by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,.image.is-3by5 img,#documenter .docs-sidebar .docs-logo>img.is-3by5 img,.image.is-3by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,.image.is-9by16 img,#documenter .docs-sidebar .docs-logo>img.is-9by16 img,.image.is-9by16 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,.image.is-1by2 img,#documenter .docs-sidebar .docs-logo>img.is-1by2 img,.image.is-1by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,.image.is-1by3 img,#documenter .docs-sidebar .docs-logo>img.is-1by3 img,.image.is-1by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}.image.is-square,#documenter .docs-sidebar .docs-logo>img.is-square,.image.is-1by1,#documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}.image.is-5by4,#documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}.image.is-4by3,#documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}.image.is-3by2,#documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}.image.is-5by3,#documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}.image.is-16by9,#documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}.image.is-2by1,#documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}.image.is-3by1,#documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}.image.is-4by5,#documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}.image.is-3by4,#documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}.image.is-2by3,#documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}.image.is-3by5,#documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}.image.is-9by16,#documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}.image.is-1by2,#documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}.image.is-1by3,#documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}.image.is-16x16,#documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}.image.is-24x24,#documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}.image.is-32x32,#documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}.image.is-48x48,#documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}.image.is-64x64,#documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}.image.is-96x96,#documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}.image.is-128x128,#documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:transparent}.notification>.delete{right:.5rem;position:absolute;top:0.5rem}.notification .title,.notification .subtitle,.notification .content{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.notification.is-dark,.content kbd.notification{background-color:#363636;color:#fff}.notification.is-primary,.docstring>section>a.notification.docs-sourcelink{background-color:#4eb5de;color:#fff}.notification.is-primary.is-light,.docstring>section>a.notification.is-light.docs-sourcelink{background-color:#eef8fc;color:#1a6d8e}.notification.is-link{background-color:#2e63b8;color:#fff}.notification.is-link.is-light{background-color:#eff3fb;color:#3169c4}.notification.is-info{background-color:#209cee;color:#fff}.notification.is-info.is-light{background-color:#ecf7fe;color:#0e72b4}.notification.is-success{background-color:#22c35b;color:#fff}.notification.is-success.is-light{background-color:#eefcf3;color:#198f43}.notification.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.notification.is-warning.is-light{background-color:#fffbeb;color:#947600}.notification.is-danger{background-color:#da0b00;color:#fff}.notification.is-danger.is-light{background-color:#ffeceb;color:#f50c00}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.progress::-webkit-progress-value{background-color:#222}.progress::-moz-progress-bar{background-color:#222}.progress::-ms-fill{background-color:#222;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #ededed 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #ededed 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right, #f5f5f5 30%, #ededed 30%)}.progress.is-dark::-webkit-progress-value,.content kbd.progress::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar,.content kbd.progress::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill,.content kbd.progress::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate,.content kbd.progress:indeterminate{background-image:linear-gradient(to right, #363636 30%, #ededed 30%)}.progress.is-primary::-webkit-progress-value,.docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#4eb5de}.progress.is-primary::-moz-progress-bar,.docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#4eb5de}.progress.is-primary::-ms-fill,.docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#4eb5de}.progress.is-primary:indeterminate,.docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #4eb5de 30%, #ededed 30%)}.progress.is-link::-webkit-progress-value{background-color:#2e63b8}.progress.is-link::-moz-progress-bar{background-color:#2e63b8}.progress.is-link::-ms-fill{background-color:#2e63b8}.progress.is-link:indeterminate{background-image:linear-gradient(to right, #2e63b8 30%, #ededed 30%)}.progress.is-info::-webkit-progress-value{background-color:#209cee}.progress.is-info::-moz-progress-bar{background-color:#209cee}.progress.is-info::-ms-fill{background-color:#209cee}.progress.is-info:indeterminate{background-image:linear-gradient(to right, #209cee 30%, #ededed 30%)}.progress.is-success::-webkit-progress-value{background-color:#22c35b}.progress.is-success::-moz-progress-bar{background-color:#22c35b}.progress.is-success::-ms-fill{background-color:#22c35b}.progress.is-success:indeterminate{background-image:linear-gradient(to right, #22c35b 30%, #ededed 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffdd57}.progress.is-warning::-moz-progress-bar{background-color:#ffdd57}.progress.is-warning::-ms-fill{background-color:#ffdd57}.progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ffdd57 30%, #ededed 30%)}.progress.is-danger::-webkit-progress-value{background-color:#da0b00}.progress.is-danger::-moz-progress-bar{background-color:#da0b00}.progress.is-danger::-ms-fill{background-color:#da0b00}.progress.is-danger:indeterminate{background-image:linear-gradient(to right, #da0b00 30%, #ededed 30%)}.progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right, #222 30%, #ededed 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress:indeterminate::-ms-fill{animation-name:none}.progress.is-small,#documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#222}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,0.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.table td.is-primary,.table th.is-primary{background-color:#4eb5de;border-color:#4eb5de;color:#fff}.table td.is-link,.table th.is-link{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.table td.is-info,.table th.is-info{background-color:#209cee;border-color:#209cee;color:#fff}.table td.is-success,.table th.is-success{background-color:#22c35b;border-color:#22c35b;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.table td.is-danger,.table th.is-danger{background-color:#da0b00;border-color:#da0b00;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#4eb5de;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.table th{color:#222}.table th:not([align]){text-align:left}.table tr.is-selected{background-color:#4eb5de;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:rgba(0,0,0,0)}.table thead td,.table thead th{border-width:0 0 2px;color:#222}.table tfoot{background-color:rgba(0,0,0,0)}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#222}.table tbody{background-color:rgba(0,0,0,0)}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:0.25em 0.5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag,.tags .content kbd,.content .tags kbd,.tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}.tags .tag:not(:last-child),.tags .content kbd:not(:last-child),.content .tags kbd:not(:last-child),.tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:.5rem}.tags:last-child{margin-bottom:-0.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large),.tags.are-medium .content kbd:not(.is-normal):not(.is-large),.content .tags.are-medium kbd:not(.is-normal):not(.is-large),.tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium),.tags.are-large .content kbd:not(.is-normal):not(.is-medium),.content .tags.are-large kbd:not(.is-normal):not(.is-medium),.tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag,.tags.is-centered .content kbd,.content .tags.is-centered kbd,.tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child),.tags.is-right .content kbd:not(:first-child),.content .tags.is-right kbd:not(:first-child),.tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}.tags.is-right .tag:not(:last-child),.tags.is-right .content kbd:not(:last-child),.content .tags.is-right kbd:not(:last-child),.tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}.tags.has-addons .tag,.tags.has-addons .content kbd,.content .tags.has-addons kbd,.tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}.tags.has-addons .tag:not(:first-child),.tags.has-addons .content kbd:not(:first-child),.content .tags.has-addons kbd:not(:first-child),.tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.tags.has-addons .tag:not(:last-child),.tags.has-addons .content kbd:not(:last-child),.content .tags.has-addons kbd:not(:last-child),.tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.tag:not(body),.content kbd:not(body),.docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#222;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}.tag:not(body) .delete,.content kbd:not(body) .delete,.docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}.tag.is-white:not(body),.content kbd.is-white:not(body),.docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}.tag.is-black:not(body),.content kbd.is-black:not(body),.docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}.tag.is-light:not(body),.content kbd.is-light:not(body),.docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.tag.is-dark:not(body),.content kbd:not(body),.docstring>section>a.docs-sourcelink.is-dark:not(body),.content .docstring>section>kbd:not(body){background-color:#363636;color:#fff}.tag.is-primary:not(body),.content kbd.is-primary:not(body),.docstring>section>a.docs-sourcelink:not(body){background-color:#4eb5de;color:#fff}.tag.is-primary.is-light:not(body),.content kbd.is-primary.is-light:not(body),.docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#eef8fc;color:#1a6d8e}.tag.is-link:not(body),.content kbd.is-link:not(body),.docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#2e63b8;color:#fff}.tag.is-link.is-light:not(body),.content kbd.is-link.is-light:not(body),.docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#eff3fb;color:#3169c4}.tag.is-info:not(body),.content kbd.is-info:not(body),.docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#209cee;color:#fff}.tag.is-info.is-light:not(body),.content kbd.is-info.is-light:not(body),.docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ecf7fe;color:#0e72b4}.tag.is-success:not(body),.content kbd.is-success:not(body),.docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#22c35b;color:#fff}.tag.is-success.is-light:not(body),.content kbd.is-success.is-light:not(body),.docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#eefcf3;color:#198f43}.tag.is-warning:not(body),.content kbd.is-warning:not(body),.docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ffdd57;color:rgba(0,0,0,0.7)}.tag.is-warning.is-light:not(body),.content kbd.is-warning.is-light:not(body),.docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffbeb;color:#947600}.tag.is-danger:not(body),.content kbd.is-danger:not(body),.docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#da0b00;color:#fff}.tag.is-danger.is-light:not(body),.content kbd.is-danger.is-light:not(body),.docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#ffeceb;color:#f50c00}.tag.is-normal:not(body),.content kbd.is-normal:not(body),.docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}.tag.is-medium:not(body),.content kbd.is-medium:not(body),.docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}.tag.is-large:not(body),.content kbd.is-large:not(body),.docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child),.content kbd:not(body) .icon:first-child:not(:last-child),.docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}.tag:not(body) .icon:last-child:not(:first-child),.content kbd:not(body) .icon:last-child:not(:first-child),.docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}.tag:not(body) .icon:first-child:last-child,.content kbd:not(body) .icon:first-child:last-child,.docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}.tag.is-delete:not(body),.content kbd.is-delete:not(body),.docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}.tag.is-delete:not(body)::before,.content kbd.is-delete:not(body)::before,.docstring>section>a.docs-sourcelink.is-delete:not(body)::before,.tag.is-delete:not(body)::after,.content kbd.is-delete:not(body)::after,.docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag.is-delete:not(body)::before,.content kbd.is-delete:not(body)::before,.docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}.tag.is-delete:not(body)::after,.content kbd.is-delete:not(body)::after,.docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}.tag.is-delete:not(body):hover,.content kbd.is-delete:not(body):hover,.docstring>section>a.docs-sourcelink.is-delete:not(body):hover,.tag.is-delete:not(body):focus,.content kbd.is-delete:not(body):focus,.docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#e8e8e8}.tag.is-delete:not(body):active,.content kbd.is-delete:not(body):active,.docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#dbdbdb}.tag.is-rounded:not(body),#documenter .docs-sidebar form.docs-search>input:not(body),.content kbd.is-rounded:not(body),#documenter .docs-sidebar .content form.docs-search>input:not(body),.docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:9999px}a.tag:hover,.docstring>section>a.docs-sourcelink:hover{text-decoration:underline}.title,.subtitle{word-break:break-word}.title em,.title span,.subtitle em,.subtitle span{font-weight:inherit}.title sub,.subtitle sub{font-size:.75em}.title sup,.subtitle sup{font-size:.75em}.title .tag,.title .content kbd,.content .title kbd,.title .docstring>section>a.docs-sourcelink,.subtitle .tag,.subtitle .content kbd,.content .subtitle kbd,.subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}.title{color:#222;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#222;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#222;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}.select select,.textarea,.input,#documenter .docs-sidebar form.docs-search>input{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#222}.select select::-moz-placeholder,.textarea::-moz-placeholder,.input::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#707070}.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder,.input::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#707070}.select select:-moz-placeholder,.textarea:-moz-placeholder,.input:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#707070}.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder,.input:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#707070}.select select:hover,.textarea:hover,.input:hover,#documenter .docs-sidebar form.docs-search>input:hover,.select select.is-hovered,.is-hovered.textarea,.is-hovered.input,#documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#b5b5b5}.select select:focus,.textarea:focus,.input:focus,#documenter .docs-sidebar form.docs-search>input:focus,.select select.is-focused,.is-focused.textarea,.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.select select:active,.textarea:active,.input:active,#documenter .docs-sidebar form.docs-search>input:active,.select select.is-active,.is-active.textarea,.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{border-color:#2e63b8;box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.select select[disabled],.textarea[disabled],.input[disabled],#documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] .select select,.select fieldset[disabled] select,fieldset[disabled] .textarea,fieldset[disabled] .input,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#6b6b6b}.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,.input[disabled]::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input::-moz-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input::-moz-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,.input[disabled]::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input::-webkit-input-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,.input[disabled]:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input:-moz-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input:-moz-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,.input[disabled]:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input:-ms-input-placeholder{color:rgba(107,107,107,0.3)}.textarea,.input,#documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 0.0625em 0.125em rgba(10,10,10,0.05);max-width:100%;width:100%}.textarea[readonly],.input[readonly],#documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}.is-white.textarea,.is-white.input,#documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}.is-white.textarea:focus,.is-white.input:focus,#documenter .docs-sidebar form.docs-search>input.is-white:focus,.is-white.is-focused.textarea,.is-white.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-white.textarea:active,.is-white.input:active,#documenter .docs-sidebar form.docs-search>input.is-white:active,.is-white.is-active.textarea,.is-white.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.is-black.textarea,.is-black.input,#documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}.is-black.textarea:focus,.is-black.input:focus,#documenter .docs-sidebar form.docs-search>input.is-black:focus,.is-black.is-focused.textarea,.is-black.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-black.textarea:active,.is-black.input:active,#documenter .docs-sidebar form.docs-search>input.is-black:active,.is-black.is-active.textarea,.is-black.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.is-light.textarea,.is-light.input,#documenter .docs-sidebar form.docs-search>input.is-light{border-color:#f5f5f5}.is-light.textarea:focus,.is-light.input:focus,#documenter .docs-sidebar form.docs-search>input.is-light:focus,.is-light.is-focused.textarea,.is-light.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-light.textarea:active,.is-light.input:active,#documenter .docs-sidebar form.docs-search>input.is-light:active,.is-light.is-active.textarea,.is-light.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.is-dark.textarea,.content kbd.textarea,.is-dark.input,#documenter .docs-sidebar form.docs-search>input.is-dark,.content kbd.input{border-color:#363636}.is-dark.textarea:focus,.content kbd.textarea:focus,.is-dark.input:focus,#documenter .docs-sidebar form.docs-search>input.is-dark:focus,.content kbd.input:focus,.is-dark.is-focused.textarea,.content kbd.is-focused.textarea,.is-dark.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.content kbd.is-focused.input,#documenter .docs-sidebar .content form.docs-search>input.is-focused,.is-dark.textarea:active,.content kbd.textarea:active,.is-dark.input:active,#documenter .docs-sidebar form.docs-search>input.is-dark:active,.content kbd.input:active,.is-dark.is-active.textarea,.content kbd.is-active.textarea,.is-dark.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.content kbd.is-active.input,#documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.is-primary.textarea,.docstring>section>a.textarea.docs-sourcelink,.is-primary.input,#documenter .docs-sidebar form.docs-search>input.is-primary,.docstring>section>a.input.docs-sourcelink{border-color:#4eb5de}.is-primary.textarea:focus,.docstring>section>a.textarea.docs-sourcelink:focus,.is-primary.input:focus,#documenter .docs-sidebar form.docs-search>input.is-primary:focus,.docstring>section>a.input.docs-sourcelink:focus,.is-primary.is-focused.textarea,.docstring>section>a.is-focused.textarea.docs-sourcelink,.is-primary.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.docstring>section>a.is-focused.input.docs-sourcelink,.is-primary.textarea:active,.docstring>section>a.textarea.docs-sourcelink:active,.is-primary.input:active,#documenter .docs-sidebar form.docs-search>input.is-primary:active,.docstring>section>a.input.docs-sourcelink:active,.is-primary.is-active.textarea,.docstring>section>a.is-active.textarea.docs-sourcelink,.is-primary.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.is-link.textarea,.is-link.input,#documenter .docs-sidebar form.docs-search>input.is-link{border-color:#2e63b8}.is-link.textarea:focus,.is-link.input:focus,#documenter .docs-sidebar form.docs-search>input.is-link:focus,.is-link.is-focused.textarea,.is-link.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-link.textarea:active,.is-link.input:active,#documenter .docs-sidebar form.docs-search>input.is-link:active,.is-link.is-active.textarea,.is-link.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.is-info.textarea,.is-info.input,#documenter .docs-sidebar form.docs-search>input.is-info{border-color:#209cee}.is-info.textarea:focus,.is-info.input:focus,#documenter .docs-sidebar form.docs-search>input.is-info:focus,.is-info.is-focused.textarea,.is-info.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-info.textarea:active,.is-info.input:active,#documenter .docs-sidebar form.docs-search>input.is-info:active,.is-info.is-active.textarea,.is-info.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.is-success.textarea,.is-success.input,#documenter .docs-sidebar form.docs-search>input.is-success{border-color:#22c35b}.is-success.textarea:focus,.is-success.input:focus,#documenter .docs-sidebar form.docs-search>input.is-success:focus,.is-success.is-focused.textarea,.is-success.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-success.textarea:active,.is-success.input:active,#documenter .docs-sidebar form.docs-search>input.is-success:active,.is-success.is-active.textarea,.is-success.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.is-warning.textarea,.is-warning.input,#documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ffdd57}.is-warning.textarea:focus,.is-warning.input:focus,#documenter .docs-sidebar form.docs-search>input.is-warning:focus,.is-warning.is-focused.textarea,.is-warning.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-warning.textarea:active,.is-warning.input:active,#documenter .docs-sidebar form.docs-search>input.is-warning:active,.is-warning.is-active.textarea,.is-warning.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.is-danger.textarea,.is-danger.input,#documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#da0b00}.is-danger.textarea:focus,.is-danger.input:focus,#documenter .docs-sidebar form.docs-search>input.is-danger:focus,.is-danger.is-focused.textarea,.is-danger.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-danger.textarea:active,.is-danger.input:active,#documenter .docs-sidebar form.docs-search>input.is-danger:active,.is-danger.is-active.textarea,.is-danger.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.is-small.textarea,.is-small.input,#documenter .docs-sidebar form.docs-search>input{border-radius:2px;font-size:.75rem}.is-medium.textarea,.is-medium.input,#documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}.is-large.textarea,.is-large.input,#documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}.is-fullwidth.textarea,.is-fullwidth.input,#documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}.is-inline.textarea,.is-inline.input,#documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}.input.is-rounded,#documenter .docs-sidebar form.docs-search>input{border-radius:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}.input.is-static,#documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:calc(0.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.radio,.checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.radio input,.checkbox input{cursor:pointer}.radio:hover,.checkbox:hover{color:#222}.radio[disabled],.checkbox[disabled],fieldset[disabled] .radio,fieldset[disabled] .checkbox,.radio input[disabled],.checkbox input[disabled]{color:#6b6b6b;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#2e63b8;right:1.125em;z-index:4}.select.is-rounded select,#documenter .docs-sidebar form.docs-search>input.select select{border-radius:9999px;padding-left:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:0.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#222}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select:hover,.select.is-white select.is-hovered{border-color:#f2f2f2}.select.is-white select:focus,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select:hover,.select.is-black select.is-hovered{border-color:#000}.select.is-black select:focus,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select:hover,.select.is-light select.is-hovered{border-color:#e8e8e8}.select.is-light select:focus,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.select.is-dark:not(:hover)::after,.content kbd.select:not(:hover)::after{border-color:#363636}.select.is-dark select,.content kbd.select select{border-color:#363636}.select.is-dark select:hover,.content kbd.select select:hover,.select.is-dark select.is-hovered,.content kbd.select select.is-hovered{border-color:#292929}.select.is-dark select:focus,.content kbd.select select:focus,.select.is-dark select.is-focused,.content kbd.select select.is-focused,.select.is-dark select:active,.content kbd.select select:active,.select.is-dark select.is-active,.content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.select.is-primary:not(:hover)::after,.docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#4eb5de}.select.is-primary select,.docstring>section>a.select.docs-sourcelink select{border-color:#4eb5de}.select.is-primary select:hover,.docstring>section>a.select.docs-sourcelink select:hover,.select.is-primary select.is-hovered,.docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#39acda}.select.is-primary select:focus,.docstring>section>a.select.docs-sourcelink select:focus,.select.is-primary select.is-focused,.docstring>section>a.select.docs-sourcelink select.is-focused,.select.is-primary select:active,.docstring>section>a.select.docs-sourcelink select:active,.select.is-primary select.is-active,.docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.select.is-link:not(:hover)::after{border-color:#2e63b8}.select.is-link select{border-color:#2e63b8}.select.is-link select:hover,.select.is-link select.is-hovered{border-color:#2958a4}.select.is-link select:focus,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.select.is-info:not(:hover)::after{border-color:#209cee}.select.is-info select{border-color:#209cee}.select.is-info select:hover,.select.is-info select.is-hovered{border-color:#1190e3}.select.is-info select:focus,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.select.is-success:not(:hover)::after{border-color:#22c35b}.select.is-success select{border-color:#22c35b}.select.is-success select:hover,.select.is-success select.is-hovered{border-color:#1ead51}.select.is-success select:focus,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.select.is-warning:not(:hover)::after{border-color:#ffdd57}.select.is-warning select{border-color:#ffdd57}.select.is-warning select:hover,.select.is-warning select.is-hovered{border-color:#ffd83e}.select.is-warning select:focus,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.select.is-danger:not(:hover)::after{border-color:#da0b00}.select.is-danger select{border-color:#da0b00}.select.is-danger select:hover,.select.is-danger select.is-hovered{border-color:#c10a00}.select.is-danger select:focus,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.select.is-small,#documenter .docs-sidebar form.docs-search>input.select{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#6b6b6b !important;opacity:0.5}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:0.625em;transform:none}.select.is-loading.is-small:after,#documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white:hover .file-cta,.file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white:focus .file-cta,.file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}.file.is-white:active .file-cta,.file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black:hover .file-cta,.file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black:focus .file-cta,.file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}.file.is-black:active .file-cta,.file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-light:hover .file-cta,.file.is-light.is-hovered .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-light:focus .file-cta,.file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(245,245,245,0.25);color:rgba(0,0,0,0.7)}.file.is-light:active .file-cta,.file.is-light.is-active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-dark .file-cta,.content kbd.file .file-cta{background-color:#363636;border-color:transparent;color:#fff}.file.is-dark:hover .file-cta,.content kbd.file:hover .file-cta,.file.is-dark.is-hovered .file-cta,.content kbd.file.is-hovered .file-cta{background-color:#2f2f2f;border-color:transparent;color:#fff}.file.is-dark:focus .file-cta,.content kbd.file:focus .file-cta,.file.is-dark.is-focused .file-cta,.content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(54,54,54,0.25);color:#fff}.file.is-dark:active .file-cta,.content kbd.file:active .file-cta,.file.is-dark.is-active .file-cta,.content kbd.file.is-active .file-cta{background-color:#292929;border-color:transparent;color:#fff}.file.is-primary .file-cta,.docstring>section>a.file.docs-sourcelink .file-cta{background-color:#4eb5de;border-color:transparent;color:#fff}.file.is-primary:hover .file-cta,.docstring>section>a.file.docs-sourcelink:hover .file-cta,.file.is-primary.is-hovered .file-cta,.docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#43b1dc;border-color:transparent;color:#fff}.file.is-primary:focus .file-cta,.docstring>section>a.file.docs-sourcelink:focus .file-cta,.file.is-primary.is-focused .file-cta,.docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(78,181,222,0.25);color:#fff}.file.is-primary:active .file-cta,.docstring>section>a.file.docs-sourcelink:active .file-cta,.file.is-primary.is-active .file-cta,.docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#39acda;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#2e63b8;border-color:transparent;color:#fff}.file.is-link:hover .file-cta,.file.is-link.is-hovered .file-cta{background-color:#2b5eae;border-color:transparent;color:#fff}.file.is-link:focus .file-cta,.file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(46,99,184,0.25);color:#fff}.file.is-link:active .file-cta,.file.is-link.is-active .file-cta{background-color:#2958a4;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#209cee;border-color:transparent;color:#fff}.file.is-info:hover .file-cta,.file.is-info.is-hovered .file-cta{background-color:#1497ed;border-color:transparent;color:#fff}.file.is-info:focus .file-cta,.file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(32,156,238,0.25);color:#fff}.file.is-info:active .file-cta,.file.is-info.is-active .file-cta{background-color:#1190e3;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#22c35b;border-color:transparent;color:#fff}.file.is-success:hover .file-cta,.file.is-success.is-hovered .file-cta{background-color:#20b856;border-color:transparent;color:#fff}.file.is-success:focus .file-cta,.file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(34,195,91,0.25);color:#fff}.file.is-success:active .file-cta,.file.is-success.is-active .file-cta{background-color:#1ead51;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-warning:hover .file-cta,.file.is-warning.is-hovered .file-cta{background-color:#ffda4a;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-warning:focus .file-cta,.file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,221,87,0.25);color:rgba(0,0,0,0.7)}.file.is-warning:active .file-cta,.file.is-warning.is-active .file-cta{background-color:#ffd83e;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-danger .file-cta{background-color:#da0b00;border-color:transparent;color:#fff}.file.is-danger:hover .file-cta,.file.is-danger.is-hovered .file-cta{background-color:#cd0a00;border-color:transparent;color:#fff}.file.is-danger:focus .file-cta,.file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(218,11,0,0.25);color:#fff}.file.is-danger:active .file-cta,.file.is-danger.is-active .file-cta{background-color:#c10a00;border-color:transparent;color:#fff}.file.is-small,#documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}.file.is-normal{font-size:1rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa,#documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#222}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#222}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#222}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#222;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:0.5em}.label.is-small,#documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:0.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark,.content kbd.help{color:#363636}.help.is-primary,.docstring>section>a.help.docs-sourcelink{color:#4eb5de}.help.is-link{color:#2e63b8}.help.is-info{color:#209cee}.help.is-success{color:#22c35b}.help.is-warning{color:#ffdd57}.help.is-danger{color:#da0b00}.field:not(:last-child){margin-bottom:0.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .button.is-hovered:not([disabled]),.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,.field.has-addons .control .input.is-hovered:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),.field.has-addons .control .select select:not([disabled]):hover,.field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .button.is-focused:not([disabled]),.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button.is-active:not([disabled]),.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,.field.has-addons .control .input.is-focused:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,.field.has-addons .control .input.is-active:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),.field.has-addons .control .select select:not([disabled]):focus,.field.has-addons .control .select select.is-focused:not([disabled]),.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select.is-active:not([disabled]){z-index:3}.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .button.is-focused:not([disabled]):hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button.is-active:not([disabled]):hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,.field.has-addons .control .input.is-focused:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,.field.has-addons .control .input.is-active:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]):focus:hover,.field.has-addons .control .select select.is-focused:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width: 768px){.field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small,#documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}.field-label.is-normal{padding-top:0.375em}.field-label.is-medium{font-size:1.25rem;padding-top:0.375em}.field-label.is-large{font-size:1.5rem;padding-top:0.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.control.has-icons-left .input:focus~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#222}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}.control.has-icons-left .input,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input,.control.has-icons-left .select select{padding-left:2.5em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input,.control.has-icons-right .select select{padding-right:2.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute !important;right:.625em;top:0.625em;z-index:4}.control.is-loading.is-small:after,#documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#2e63b8;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#222;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ul,.breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:.5em}.breadcrumb .icon:last-child{margin-left:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small,#documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;border-radius:.25rem;box-shadow:#bbb;color:#222;max-width:100%;position:relative}.card-footer:first-child,.card-content:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-footer:last-child,.card-content:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);display:flex}.card-header-title{align-items:center;color:#222;display:flex;flex-grow:1;font-weight:700;padding:0.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-content{background-color:rgba(0,0,0,0);padding:1.5rem}.card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #ededed;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #ededed}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:#bbb;padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#222;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#2e63b8;color:#fff}.dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:0.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .title,.level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,0.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,0.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width: 768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small,#documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#222;display:block;padding:0.5em 0.75em}.menu-list a:hover{background-color:#f5f5f5;color:#222}.menu-list a.is-active{background-color:#2e63b8;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#6b6b6b;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small,#documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark,.content kbd.message{background-color:#fafafa}.message.is-dark .message-header,.content kbd.message .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body,.content kbd.message .message-body{border-color:#363636}.message.is-primary,.docstring>section>a.message.docs-sourcelink{background-color:#eef8fc}.message.is-primary .message-header,.docstring>section>a.message.docs-sourcelink .message-header{background-color:#4eb5de;color:#fff}.message.is-primary .message-body,.docstring>section>a.message.docs-sourcelink .message-body{border-color:#4eb5de;color:#1a6d8e}.message.is-link{background-color:#eff3fb}.message.is-link .message-header{background-color:#2e63b8;color:#fff}.message.is-link .message-body{border-color:#2e63b8;color:#3169c4}.message.is-info{background-color:#ecf7fe}.message.is-info .message-header{background-color:#209cee;color:#fff}.message.is-info .message-body{border-color:#209cee;color:#0e72b4}.message.is-success{background-color:#eefcf3}.message.is-success .message-header{background-color:#22c35b;color:#fff}.message.is-success .message-body{border-color:#22c35b;color:#198f43}.message.is-warning{background-color:#fffbeb}.message.is-warning .message-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.message.is-warning .message-body{border-color:#ffdd57;color:#947600}.message.is-danger{background-color:#ffeceb}.message.is-danger .message-header{background-color:#da0b00;color:#fff}.message.is-danger .message-body{border-color:#da0b00;color:#f50c00}.message-header{align-items:center;background-color:#222;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#222;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:rgba(0,0,0,0)}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,0.86)}.modal-content,.modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px){.modal-content,.modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-head,.modal-card-foot{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#222;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand>.navbar-item,.navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){.navbar.is-white .navbar-start>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-start .navbar-link::after,.navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand>.navbar-item,.navbar.is-black .navbar-brand .navbar-link{color:#fff}.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-black .navbar-start>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-end .navbar-link{color:#fff}.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-start .navbar-link::after,.navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand>.navbar-item,.navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){.navbar.is-light .navbar-start>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end .navbar-link.is-active{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-start .navbar-link::after,.navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}}.navbar.is-dark,.content kbd.navbar{background-color:#363636;color:#fff}.navbar.is-dark .navbar-brand>.navbar-item,.content kbd.navbar .navbar-brand>.navbar-item,.navbar.is-dark .navbar-brand .navbar-link,.content kbd.navbar .navbar-brand .navbar-link{color:#fff}.navbar.is-dark .navbar-brand>a.navbar-item:focus,.content kbd.navbar .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover,.content kbd.navbar .navbar-brand>a.navbar-item:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.content kbd.navbar .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.content kbd.navbar .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.content kbd.navbar .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand .navbar-link.is-active,.content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#292929;color:#fff}.navbar.is-dark .navbar-brand .navbar-link::after,.content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger,.content kbd.navbar .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-dark .navbar-start>.navbar-item,.content kbd.navbar .navbar-start>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.content kbd.navbar .navbar-start .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.content kbd.navbar .navbar-end>.navbar-item,.navbar.is-dark .navbar-end .navbar-link,.content kbd.navbar .navbar-end .navbar-link{color:#fff}.navbar.is-dark .navbar-start>a.navbar-item:focus,.content kbd.navbar .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover,.content kbd.navbar .navbar-start>a.navbar-item:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.content kbd.navbar .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.content kbd.navbar .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.content kbd.navbar .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.content kbd.navbar .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.content kbd.navbar .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.content kbd.navbar .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.content kbd.navbar .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.content kbd.navbar .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.content kbd.navbar .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end .navbar-link.is-active,.content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#292929;color:#fff}.navbar.is-dark .navbar-start .navbar-link::after,.content kbd.navbar .navbar-start .navbar-link::after,.navbar.is-dark .navbar-end .navbar-link::after,.content kbd.navbar .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,.content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#292929;color:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active,.content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.navbar.is-primary,.docstring>section>a.navbar.docs-sourcelink{background-color:#4eb5de;color:#fff}.navbar.is-primary .navbar-brand>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,.navbar.is-primary .navbar-brand .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}.navbar.is-primary .navbar-brand>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger,.docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-primary .navbar-start>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,.navbar.is-primary .navbar-end .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}.navbar.is-primary .navbar-start>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-start .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,.navbar.is-primary .navbar-end .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#4eb5de;color:#fff}}.navbar.is-link{background-color:#2e63b8;color:#fff}.navbar.is-link .navbar-brand>.navbar-item,.navbar.is-link .navbar-brand .navbar-link{color:#fff}.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-link .navbar-start>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-end .navbar-link{color:#fff}.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end .navbar-link.is-active{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-start .navbar-link::after,.navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#2e63b8;color:#fff}}.navbar.is-info{background-color:#209cee;color:#fff}.navbar.is-info .navbar-brand>.navbar-item,.navbar.is-info .navbar-brand .navbar-link{color:#fff}.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-info .navbar-start>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-end .navbar-link{color:#fff}.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end .navbar-link.is-active{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-start .navbar-link::after,.navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#209cee;color:#fff}}.navbar.is-success{background-color:#22c35b;color:#fff}.navbar.is-success .navbar-brand>.navbar-item,.navbar.is-success .navbar-brand .navbar-link{color:#fff}.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-success .navbar-start>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-end .navbar-link{color:#fff}.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end .navbar-link.is-active{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-start .navbar-link::after,.navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#22c35b;color:#fff}}.navbar.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>.navbar-item,.navbar.is-warning .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){.navbar.is-warning .navbar-start>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start .navbar-link::after,.navbar.is-warning .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffdd57;color:rgba(0,0,0,0.7)}}.navbar.is-danger{background-color:#da0b00;color:#fff}.navbar.is-danger .navbar-brand>.navbar-item,.navbar.is-danger .navbar-brand .navbar-link{color:#fff}.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-danger .navbar-start>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-end .navbar-link{color:#fff}.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-start .navbar-link::after,.navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#da0b00;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}html.has-navbar-fixed-top,body.has-navbar-fixed-top{padding-top:3.25rem}html.has-navbar-fixed-bottom,body.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#222;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,0.05)}.navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#222;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}a.navbar-item,.navbar-link{cursor:pointer}a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover,a.navbar-item.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,.navbar-link.is-active{background-color:#fafafa;color:#2e63b8}.navbar-item{flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(0.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#2e63b8}.navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#2e63b8;border-bottom-style:solid;border-bottom-width:3px;color:#2e63b8;padding-bottom:calc(0.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#2e63b8;margin-top:-0.375em;right:1.125em}.navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}html.has-navbar-fixed-top-touch,body.has-navbar-fixed-top-touch{padding-top:3.25rem}html.has-navbar-fixed-bottom-touch,body.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width: 1056px){.navbar,.navbar-menu,.navbar-start,.navbar-end{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-start,.navbar.is-spaced .navbar-end{align-items:center}.navbar.is-spaced a.navbar-item,.navbar.is-spaced .navbar-link{border-radius:4px}.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#2e63b8}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#2e63b8}.navbar.is-spaced .navbar-dropdown,.navbar-dropdown.is-boxed{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.navbar>.container .navbar-brand,.container>.navbar .navbar-brand{margin-left:-.75rem}.navbar>.container .navbar-menu,.container>.navbar .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-desktop{top:0}html.has-navbar-fixed-top-desktop,body.has-navbar-fixed-top-desktop{padding-top:3.25rem}html.has-navbar-fixed-bottom-desktop,body.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}html.has-spaced-navbar-fixed-top,body.has-spaced-navbar-fixed-top{padding-top:5.25rem}html.has-spaced-navbar-fixed-bottom,body.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}a.navbar-item.is-active,.navbar-link.is-active{color:#0a0a0a}a.navbar-item.is-active:not(:focus):not(:hover),.navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link,.navbar-item.has-dropdown.is-active .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small,#documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-previous,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,.pagination.is-rounded .pagination-next,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:9999px}.pagination.is-rounded .pagination-link,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-previous,.pagination-next,.pagination-link{border-color:#dbdbdb;color:#222;min-width:2.5em}.pagination-previous:hover,.pagination-next:hover,.pagination-link:hover{border-color:#b5b5b5;color:#363636}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus{border-color:#3c5dcd}.pagination-previous:active,.pagination-next:active,.pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}.pagination-previous[disabled],.pagination-previous.is-disabled,.pagination-next[disabled],.pagination-next.is-disabled,.pagination-link[disabled],.pagination-link.is-disabled{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#6b6b6b;opacity:0.5}.pagination-previous,.pagination-next{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}.pagination-list li{list-style:none}@media screen and (max-width: 768px){.pagination{flex-wrap:wrap}.pagination-previous,.pagination-next{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{border-radius:6px;box-shadow:#bbb;font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading,.content kbd.panel .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active,.content kbd.panel .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon,.content kbd.panel .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading,.docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#4eb5de;color:#fff}.panel.is-primary .panel-tabs a.is-active,.docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#4eb5de}.panel.is-primary .panel-block.is-active .panel-icon,.docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#4eb5de}.panel.is-link .panel-heading{background-color:#2e63b8;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#2e63b8}.panel.is-link .panel-block.is-active .panel-icon{color:#2e63b8}.panel.is-info .panel-heading{background-color:#209cee;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#209cee}.panel.is-info .panel-block.is-active .panel-icon{color:#209cee}.panel.is-success .panel-heading{background-color:#22c35b;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#22c35b}.panel.is-success .panel-block.is-active .panel-icon{color:#22c35b}.panel.is-warning .panel-heading{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffdd57}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffdd57}.panel.is-danger .panel-heading{background-color:#da0b00;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#da0b00}.panel.is-danger .panel-block.is-active .panel-icon{color:#da0b00}.panel-tabs:not(:last-child),.panel-block:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#222;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:0.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#222}.panel-list a:hover{color:#2e63b8}.panel-block{align-items:center;color:#222;display:flex;justify-content:flex-start;padding:0.5em 0.75em}.panel-block input[type="checkbox"]{margin-right:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#2e63b8;color:#363636}.panel-block.is-active .panel-icon{color:#2e63b8}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#6b6b6b;margin-right:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#222;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#222;color:#222}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#2e63b8;color:#2e63b8}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:0.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}.tabs .icon:first-child{margin-right:.5em}.tabs .icon:last-child{margin-left:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:rgba(0,0,0,0) !important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li:last-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.tabs.is-toggle li.is-active a{background-color:#2e63b8;border-color:#2e63b8;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}.tabs.is-small,#documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none;width:unset}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-left:0%}.columns.is-mobile>.column.is-1{flex:none;width:8.33333337%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>.column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66666674%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333337%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>.column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66666674%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333337%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>.column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66666674%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333337%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>.column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66666674%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){.column.is-narrow-mobile{flex:none;width:unset}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-left:0%}.column.is-1-mobile{flex:none;width:8.33333337%}.column.is-offset-1-mobile{margin-left:8.33333337%}.column.is-2-mobile{flex:none;width:16.66666674%}.column.is-offset-2-mobile{margin-left:16.66666674%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333337%}.column.is-offset-4-mobile{margin-left:33.33333337%}.column.is-5-mobile{flex:none;width:41.66666674%}.column.is-offset-5-mobile{margin-left:41.66666674%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333337%}.column.is-offset-7-mobile{margin-left:58.33333337%}.column.is-8-mobile{flex:none;width:66.66666674%}.column.is-offset-8-mobile{margin-left:66.66666674%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333337%}.column.is-offset-10-mobile{margin-left:83.33333337%}.column.is-11-mobile{flex:none;width:91.66666674%}.column.is-offset-11-mobile{margin-left:91.66666674%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none;width:unset}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-left:0%}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333337%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333337%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66666674%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66666674%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333337%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333337%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66666674%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66666674%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333337%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333337%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66666674%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66666674%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333337%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333337%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66666674%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66666674%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){.column.is-narrow-touch{flex:none;width:unset}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-left:0%}.column.is-1-touch{flex:none;width:8.33333337%}.column.is-offset-1-touch{margin-left:8.33333337%}.column.is-2-touch{flex:none;width:16.66666674%}.column.is-offset-2-touch{margin-left:16.66666674%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333337%}.column.is-offset-4-touch{margin-left:33.33333337%}.column.is-5-touch{flex:none;width:41.66666674%}.column.is-offset-5-touch{margin-left:41.66666674%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333337%}.column.is-offset-7-touch{margin-left:58.33333337%}.column.is-8-touch{flex:none;width:66.66666674%}.column.is-offset-8-touch{margin-left:66.66666674%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333337%}.column.is-offset-10-touch{margin-left:83.33333337%}.column.is-11-touch{flex:none;width:91.66666674%}.column.is-offset-11-touch{margin-left:91.66666674%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){.column.is-narrow-desktop{flex:none;width:unset}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-left:0%}.column.is-1-desktop{flex:none;width:8.33333337%}.column.is-offset-1-desktop{margin-left:8.33333337%}.column.is-2-desktop{flex:none;width:16.66666674%}.column.is-offset-2-desktop{margin-left:16.66666674%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333337%}.column.is-offset-4-desktop{margin-left:33.33333337%}.column.is-5-desktop{flex:none;width:41.66666674%}.column.is-offset-5-desktop{margin-left:41.66666674%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333337%}.column.is-offset-7-desktop{margin-left:58.33333337%}.column.is-8-desktop{flex:none;width:66.66666674%}.column.is-offset-8-desktop{margin-left:66.66666674%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333337%}.column.is-offset-10-desktop{margin-left:83.33333337%}.column.is-11-desktop{flex:none;width:91.66666674%}.column.is-offset-11-desktop{margin-left:91.66666674%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){.column.is-narrow-widescreen{flex:none;width:unset}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-left:0%}.column.is-1-widescreen{flex:none;width:8.33333337%}.column.is-offset-1-widescreen{margin-left:8.33333337%}.column.is-2-widescreen{flex:none;width:16.66666674%}.column.is-offset-2-widescreen{margin-left:16.66666674%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333337%}.column.is-offset-4-widescreen{margin-left:33.33333337%}.column.is-5-widescreen{flex:none;width:41.66666674%}.column.is-offset-5-widescreen{margin-left:41.66666674%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333337%}.column.is-offset-7-widescreen{margin-left:58.33333337%}.column.is-8-widescreen{flex:none;width:66.66666674%}.column.is-offset-8-widescreen{margin-left:66.66666674%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333337%}.column.is-offset-10-widescreen{margin-left:83.33333337%}.column.is-11-widescreen{flex:none;width:91.66666674%}.column.is-offset-11-widescreen{margin-left:91.66666674%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){.column.is-narrow-fullhd{flex:none;width:unset}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-left:0%}.column.is-1-fullhd{flex:none;width:8.33333337%}.column.is-offset-1-fullhd{margin-left:8.33333337%}.column.is-2-fullhd{flex:none;width:16.66666674%}.column.is-offset-2-fullhd{margin-left:16.66666674%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333337%}.column.is-offset-4-fullhd{margin-left:33.33333337%}.column.is-5-fullhd{flex:none;width:41.66666674%}.column.is-offset-5-fullhd{margin-left:41.66666674%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333337%}.column.is-offset-7-fullhd{margin-left:58.33333337%}.column.is-8-fullhd{flex:none;width:66.66666674%}.column.is-offset-8-fullhd{margin-left:66.66666674%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333337%}.column.is-offset-10-fullhd{margin-left:83.33333337%}.column.is-11-fullhd{flex:none;width:91.66666674%}.column.is-offset-11-fullhd{margin-left:91.66666674%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0 !important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){.columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-0-fullhd{--columnGap: 0rem}}.columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){.columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-1-fullhd{--columnGap: .25rem}}.columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){.columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-2-fullhd{--columnGap: .5rem}}.columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){.columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-3-fullhd{--columnGap: .75rem}}.columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){.columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-4-fullhd{--columnGap: 1rem}}.columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){.columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}.columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){.columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}.columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){.columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}.columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){.columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-8-fullhd{--columnGap: 2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0 !important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333337%}.tile.is-2{flex:none;width:16.66666674%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333337%}.tile.is-5{flex:none;width:41.66666674%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333337%}.tile.is-8{flex:none;width:66.66666674%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333337%}.tile.is-11{flex:none;width:91.66666674%}.tile.is-12{flex:none;width:100%}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:none}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,0.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}.hero.is-white a.navbar-item:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white .navbar-link:hover,.hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{color:#fff !important;opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,0.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-black a.navbar-item:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black .navbar-link:hover,.hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:0.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{color:#0a0a0a !important;opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:rgba(0,0,0,0.7)}.hero.is-light .subtitle{color:rgba(0,0,0,0.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(0,0,0,0.7)}.hero.is-light a.navbar-item:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light .navbar-link:hover,.hero.is-light .navbar-link.is-active{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5 !important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}}.hero.is-dark,.content kbd.hero{background-color:#363636;color:#fff}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong,.content kbd.hero strong{color:inherit}.hero.is-dark .title,.content kbd.hero .title{color:#fff}.hero.is-dark .subtitle,.content kbd.hero .subtitle{color:rgba(255,255,255,0.9)}.hero.is-dark .subtitle a:not(.button),.content kbd.hero .subtitle a:not(.button),.hero.is-dark .subtitle strong,.content kbd.hero .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-dark .navbar-menu,.content kbd.hero .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.content kbd.hero .navbar-item,.hero.is-dark .navbar-link,.content kbd.hero .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-dark a.navbar-item:hover,.content kbd.hero a.navbar-item:hover,.hero.is-dark a.navbar-item.is-active,.content kbd.hero a.navbar-item.is-active,.hero.is-dark .navbar-link:hover,.content kbd.hero .navbar-link:hover,.hero.is-dark .navbar-link.is-active,.content kbd.hero .navbar-link.is-active{background-color:#292929;color:#fff}.hero.is-dark .tabs a,.content kbd.hero .tabs a{color:#fff;opacity:0.9}.hero.is-dark .tabs a:hover,.content kbd.hero .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a,.content kbd.hero .tabs li.is-active a{color:#363636 !important;opacity:1}.hero.is-dark .tabs.is-boxed a,.content kbd.hero .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a,.content kbd.hero .tabs.is-toggle a{color:#fff}.hero.is-dark .tabs.is-boxed a:hover,.content kbd.hero .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover,.content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.content kbd.hero .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.content kbd.hero .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#363636}.hero.is-dark.is-bold,.content kbd.hero.is-bold{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}@media screen and (max-width: 768px){.hero.is-dark.is-bold .navbar-menu,.content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}}.hero.is-primary,.docstring>section>a.hero.docs-sourcelink{background-color:#4eb5de;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong,.docstring>section>a.hero.docs-sourcelink strong{color:inherit}.hero.is-primary .title,.docstring>section>a.hero.docs-sourcelink .title{color:#fff}.hero.is-primary .subtitle,.docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}.hero.is-primary .subtitle a:not(.button),.docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),.hero.is-primary .subtitle strong,.docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-primary .navbar-menu,.docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#4eb5de}}.hero.is-primary .navbar-item,.docstring>section>a.hero.docs-sourcelink .navbar-item,.hero.is-primary .navbar-link,.docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-primary a.navbar-item:hover,.docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,.hero.is-primary a.navbar-item.is-active,.docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,.hero.is-primary .navbar-link:hover,.docstring>section>a.hero.docs-sourcelink .navbar-link:hover,.hero.is-primary .navbar-link.is-active,.docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#39acda;color:#fff}.hero.is-primary .tabs a,.docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}.hero.is-primary .tabs a:hover,.docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{color:#4eb5de !important;opacity:1}.hero.is-primary .tabs.is-boxed a,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#4eb5de}.hero.is-primary.is-bold,.docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #1bc7de 0%, #4eb5de 71%, #5fa9e7 100%)}@media screen and (max-width: 768px){.hero.is-primary.is-bold .navbar-menu,.docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #1bc7de 0%, #4eb5de 71%, #5fa9e7 100%)}}.hero.is-link{background-color:#2e63b8;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,0.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-link .navbar-menu{background-color:#2e63b8}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-link a.navbar-item:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link .navbar-link:hover,.hero.is-link .navbar-link.is-active{background-color:#2958a4;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:0.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{color:#2e63b8 !important;opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#2e63b8}.hero.is-link.is-bold{background-image:linear-gradient(141deg, #1b6098 0%, #2e63b8 71%, #2d51d2 100%)}@media screen and (max-width: 768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1b6098 0%, #2e63b8 71%, #2d51d2 100%)}}.hero.is-info{background-color:#209cee;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,0.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-info .navbar-menu{background-color:#209cee}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-info a.navbar-item:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info .navbar-link:hover,.hero.is-info .navbar-link.is-active{background-color:#1190e3;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:0.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{color:#209cee !important;opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#209cee}.hero.is-info.is-bold{background-image:linear-gradient(141deg, #05a6d6 0%, #209cee 71%, #3287f5 100%)}@media screen and (max-width: 768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #05a6d6 0%, #209cee 71%, #3287f5 100%)}}.hero.is-success{background-color:#22c35b;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,0.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-success .navbar-menu{background-color:#22c35b}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-success a.navbar-item:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success .navbar-link:hover,.hero.is-success .navbar-link.is-active{background-color:#1ead51;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:0.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{color:#22c35b !important;opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#22c35b}.hero.is-success.is-bold{background-image:linear-gradient(141deg, #12a02c 0%, #22c35b 71%, #1fdf83 100%)}@media screen and (max-width: 768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #12a02c 0%, #22c35b 71%, #1fdf83 100%)}}.hero.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,0.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,0.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){.hero.is-warning .navbar-menu{background-color:#ffdd57}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,0.7)}.hero.is-warning a.navbar-item:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{color:#ffdd57 !important;opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ffdd57}.hero.is-warning.is-bold{background-image:linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%)}@media screen and (max-width: 768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%)}}.hero.is-danger{background-color:#da0b00;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-danger .navbar-menu{background-color:#da0b00}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-danger a.navbar-item:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger .navbar-link.is-active{background-color:#c10a00;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:0.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{color:#da0b00 !important;opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#da0b00}.hero.is-danger.is-bold{background-image:linear-gradient(141deg, #a70013 0%, #da0b00 71%, #f43500 100%)}@media screen and (max-width: 768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #a70013 0%, #da0b00 71%, #f43500 100%)}}.hero.is-small .hero-body,#documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding:1.5rem}@media screen and (min-width: 769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.hero.is-halfheight .hero-body,.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}.hero.is-halfheight .hero-body>.container,.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}.hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-head,.hero-foot{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width: 769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem}h1 .docs-heading-anchor,h1 .docs-heading-anchor:hover,h1 .docs-heading-anchor:visited,h2 .docs-heading-anchor,h2 .docs-heading-anchor:hover,h2 .docs-heading-anchor:visited,h3 .docs-heading-anchor,h3 .docs-heading-anchor:hover,h3 .docs-heading-anchor:visited,h4 .docs-heading-anchor,h4 .docs-heading-anchor:hover,h4 .docs-heading-anchor:visited,h5 .docs-heading-anchor,h5 .docs-heading-anchor:hover,h5 .docs-heading-anchor:visited,h6 .docs-heading-anchor,h6 .docs-heading-anchor:hover,h6 .docs-heading-anchor:visited{color:#222}h1 .docs-heading-anchor-permalink,h2 .docs-heading-anchor-permalink,h3 .docs-heading-anchor-permalink,h4 .docs-heading-anchor-permalink,h5 .docs-heading-anchor-permalink,h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}h1 .docs-heading-anchor-permalink::before,h2 .docs-heading-anchor-permalink::before,h3 .docs-heading-anchor-permalink::before,h4 .docs-heading-anchor-permalink::before,h5 .docs-heading-anchor-permalink::before,h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f0c1"}h1:hover .docs-heading-anchor-permalink,h2:hover .docs-heading-anchor-permalink,h3:hover .docs-heading-anchor-permalink,h4:hover .docs-heading-anchor-permalink,h5:hover .docs-heading-anchor-permalink,h6:hover .docs-heading-anchor-permalink{visibility:visible}.docs-dark-only{display:none !important}pre{position:relative;overflow:hidden}pre code,pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}pre code:first-of-type,pre code.hljs:first-of-type{padding-top:0.5rem !important}pre code:last-of-type,pre code.hljs:last-of-type{padding-bottom:0.5rem !important}pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 6 Free";color:#222;cursor:pointer;text-align:center}pre .copy-button:focus,pre .copy-button:hover{opacity:1;background:rgba(34,34,34,0.1);color:#2e63b8}pre .copy-button.success{color:#259a12;opacity:1}pre .copy-button.error{color:#cb3c33;opacity:1}pre:hover .copy-button{opacity:1}.admonition{background-color:#b5b5b5;border-style:solid;border-width:1px;border-color:#363636;border-radius:4px;font-size:1rem}.admonition strong{color:currentColor}.admonition.is-small,#documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}.admonition.is-medium{font-size:1.25rem}.admonition.is-large{font-size:1.5rem}.admonition.is-default{background-color:#b5b5b5;border-color:#363636}.admonition.is-default>.admonition-header{background-color:#363636;color:#fff}.admonition.is-default>.admonition-body{color:#fff}.admonition.is-info{background-color:#def0fc;border-color:#209cee}.admonition.is-info>.admonition-header{background-color:#209cee;color:#fff}.admonition.is-info>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-success{background-color:#bdf4d1;border-color:#22c35b}.admonition.is-success>.admonition-header{background-color:#22c35b;color:#fff}.admonition.is-success>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-warning{background-color:#fff3c5;border-color:#ffdd57}.admonition.is-warning>.admonition-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.admonition.is-warning>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-danger{background-color:#ffaba7;border-color:#da0b00}.admonition.is-danger>.admonition-header{background-color:#da0b00;color:#fff}.admonition.is-danger>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-compat{background-color:#bdeff5;border-color:#1db5c9}.admonition.is-compat>.admonition-header{background-color:#1db5c9;color:#fff}.admonition.is-compat>.admonition-body{color:rgba(0,0,0,0.7)}.admonition-header{color:#fff;background-color:#363636;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}details.admonition.is-details>.admonition-header{list-style:none}details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}.admonition-body{color:#222;padding:0.5rem .75rem}.admonition-body pre{background-color:#f5f5f5}.admonition-body code{background-color:rgba(0,0,0,0.05)}.docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #dbdbdb;box-shadow:2px 2px 3px rgba(10,10,10,0.1);max-width:100%}.docstring>header{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#f5f5f5;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #dbdbdb;overflow:auto}.docstring>header code{background-color:transparent}.docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}.docstring>header .docstring-binding{margin-right:0.3em}.docstring>header .docstring-category{margin-left:0.3em}.docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #dbdbdb}.docstring>section:last-child{border-bottom:none}.docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}.docstring>section>a.docs-sourcelink:focus{opacity:1 !important}.docstring:hover>section>a.docs-sourcelink{opacity:0.2}.docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}.docstring>section:hover a.docs-sourcelink{opacity:1}.documenter-example-output{background-color:#fff}.outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#ffaba7;color:rgba(0,0,0,0.7);border-bottom:3px solid #da0b00;padding:10px 35px;text-align:center;font-size:15px}.outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}.outdated-warning-overlay a{color:#2e63b8}.outdated-warning-overlay a:hover{color:#363636}.content pre{border:1px solid #dbdbdb}.content code{font-weight:inherit}.content a code{color:#2e63b8}.content a:hover code{color:#363636}.content h1 code,.content h2 code,.content h3 code,.content h4 code,.content h5 code,.content h6 code{color:#222}.content table{display:block;width:initial;max-width:100%;overflow-x:auto}.content blockquote>ul:first-child,.content blockquote>ol:first-child,.content .admonition-body>ul:first-child,.content .admonition-body>ol:first-child{margin-top:0}pre,code{font-variant-ligatures:no-contextual}.breadcrumb a.is-disabled{cursor:default;pointer-events:none}.breadcrumb a.is-disabled,.breadcrumb a.is-disabled:hover{color:#222}.hljs{background:initial !important}.katex .katex-mathml{top:0;right:0}.katex-display,mjx-container,.MathJax_Display{margin:0.5em 0 !important}html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}li.no-marker{list-style:none}#documenter .docs-main>article{overflow-wrap:break-word}#documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){#documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){#documenter .docs-main{width:100%}#documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}#documenter .docs-main>header,#documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}#documenter .docs-main header.docs-navbar{background-color:#fff;border-bottom:1px solid #dbdbdb;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}#documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1;overflow-x:hidden}#documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}#documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}#documenter .docs-main header.docs-navbar .docs-right .docs-icon,#documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}#documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){#documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}#documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){#documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}#documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #bbb;transition-duration:0.7s;-webkit-transition-duration:0.7s}#documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}#documenter .docs-main section.footnotes{border-top:1px solid #dbdbdb}#documenter .docs-main section.footnotes li .tag:first-child,#documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,#documenter .docs-main section.footnotes li .content kbd:first-child,.content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}#documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #dbdbdb;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){#documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}#documenter .docs-main .docs-footer .docs-footer-nextpage,#documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}#documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}#documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}#documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}#documenter .docs-sidebar{display:flex;flex-direction:column;color:#0a0a0a;background-color:#f5f5f5;border-right:1px solid #dbdbdb;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}#documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #bbb}@media screen and (min-width: 1056px){#documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){#documenter .docs-sidebar{left:0;top:0}}#documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}#documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}#documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}#documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}#documenter .docs-sidebar .docs-package-name a,#documenter .docs-sidebar .docs-package-name a:hover{color:#0a0a0a}#documenter .docs-sidebar .docs-version-selector{border-top:1px solid #dbdbdb;display:none;padding:0.5rem}#documenter .docs-sidebar .docs-version-selector.visible{display:flex}#documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #dbdbdb;padding-bottom:1.5rem}#documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}#documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #dbdbdb}#documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}#documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}#documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}#documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f054"}#documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}#documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}#documenter .docs-sidebar ul.docs-menu .tocitem,#documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#0a0a0a;background:#f5f5f5}#documenter .docs-sidebar ul.docs-menu a.tocitem:hover,#documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#0a0a0a;background-color:#ebebeb}#documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #dbdbdb;border-bottom:1px solid #dbdbdb;background-color:#fff}#documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,#documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#fff;color:#0a0a0a}#documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#ebebeb;color:#0a0a0a}#documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}#documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #dbdbdb}#documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}#documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}#documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}#documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}#documenter .docs-sidebar form.docs-search>input{width:14.4rem}#documenter .docs-sidebar #documenter-search-query{color:#707070;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@media screen and (min-width: 1056px){#documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#e0e0e0}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#ccc}}@media screen and (max-width: 1055px){#documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}#documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}#documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#e0e0e0}#documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#ccc}}kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(0,0,0,0.6);box-shadow:0 2px 0 1px rgba(0,0,0,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}.search-min-width-50{min-width:50%}.search-min-height-100{min-height:100%}.search-modal-card-body{max-height:calc(100vh - 15rem)}.search-result-link{border-radius:0.7em;transition:all 300ms}.search-result-link:hover,.search-result-link:focus{background-color:rgba(0,128,128,0.1)}.search-result-link .property-search-result-badge,.search-result-link .search-filter{transition:all 300ms}.property-search-result-badge,.search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}.search-result-link:hover .property-search-result-badge,.search-result-link:hover .search-filter,.search-result-link:focus .property-search-result-badge,.search-result-link:focus .search-filter{color:#f1f5f9;background-color:#333}.search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}.search-filter:hover,.search-filter:focus{color:#333}.search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}.search-filter-selected:hover,.search-filter-selected:focus{color:#f5f5f5}.search-result-highlight{background-color:#ffdd57;color:black}.search-divider{border-bottom:1px solid #dbdbdb}.search-result-title{width:85%;color:#333}.search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}#search-modal .modal-card-body::-webkit-scrollbar,#search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}#search-modal .modal-card-body::-webkit-scrollbar-thumb,#search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}#search-modal .modal-card-body::-webkit-scrollbar-track,#search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}.w-100{width:100%}.gap-2{gap:0.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.ansi span.sgr1{font-weight:bolder}.ansi span.sgr2{font-weight:lighter}.ansi span.sgr3{font-style:italic}.ansi span.sgr4{text-decoration:underline}.ansi span.sgr7{color:#fff;background-color:#222}.ansi span.sgr8{color:transparent}.ansi span.sgr8 span{color:transparent}.ansi span.sgr9{text-decoration:line-through}.ansi span.sgr30{color:#242424}.ansi span.sgr31{color:#a7201f}.ansi span.sgr32{color:#066f00}.ansi span.sgr33{color:#856b00}.ansi span.sgr34{color:#2149b0}.ansi span.sgr35{color:#7d4498}.ansi span.sgr36{color:#007989}.ansi span.sgr37{color:gray}.ansi span.sgr40{background-color:#242424}.ansi span.sgr41{background-color:#a7201f}.ansi span.sgr42{background-color:#066f00}.ansi span.sgr43{background-color:#856b00}.ansi span.sgr44{background-color:#2149b0}.ansi span.sgr45{background-color:#7d4498}.ansi span.sgr46{background-color:#007989}.ansi span.sgr47{background-color:gray}.ansi span.sgr90{color:#616161}.ansi span.sgr91{color:#cb3c33}.ansi span.sgr92{color:#0e8300}.ansi span.sgr93{color:#a98800}.ansi span.sgr94{color:#3c5dcd}.ansi span.sgr95{color:#9256af}.ansi span.sgr96{color:#008fa3}.ansi span.sgr97{color:#f5f5f5}.ansi span.sgr100{background-color:#616161}.ansi span.sgr101{background-color:#cb3c33}.ansi span.sgr102{background-color:#0e8300}.ansi span.sgr103{background-color:#a98800}.ansi span.sgr104{background-color:#3c5dcd}.ansi span.sgr105{background-color:#9256af}.ansi span.sgr106{background-color:#008fa3}.ansi span.sgr107{background-color:#f5f5f5}code.language-julia-repl>span.hljs-meta{color:#066f00;font-weight:bolder}/*! + Theme: Default + Description: Original highlight.js style + Author: (c) Ivan Sagalaev + Maintainer: @highlightjs/core-team + Website: https://highlightjs.org/ + License: see project LICENSE + Touched: 2021 +*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#F3F3F3;color:#444}.hljs-comment{color:#697070}.hljs-tag,.hljs-punctuation{color:#444a}.hljs-tag .hljs-name,.hljs-tag .hljs-attr{color:#444}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-operator,.hljs-selector-pseudo{color:#ab5656}.hljs-literal{color:#695}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.gap-4{gap:1rem} diff --git a/v0.16.12/assets/themeswap.js b/v0.16.12/assets/themeswap.js new file mode 100644 index 000000000..9f5eebe6a --- /dev/null +++ b/v0.16.12/assets/themeswap.js @@ -0,0 +1,84 @@ +// Small function to quickly swap out themes. Gets put into the tag.. +function set_theme_from_local_storage() { + // Initialize the theme to null, which means default + var theme = null; + // If the browser supports the localstorage and is not disabled then try to get the + // documenter theme + if (window.localStorage != null) { + // Get the user-picked theme from localStorage. May be `null`, which means the default + // theme. + theme = window.localStorage.getItem("documenter-theme"); + } + // Check if the users preference is for dark color scheme + var darkPreference = + window.matchMedia("(prefers-color-scheme: dark)").matches === true; + // Initialize a few variables for the loop: + // + // - active: will contain the index of the theme that should be active. Note that there + // is no guarantee that localStorage contains sane values. If `active` stays `null` + // we either could not find the theme or it is the default (primary) theme anyway. + // Either way, we then need to stick to the primary theme. + // + // - disabled: style sheets that should be disabled (i.e. all the theme style sheets + // that are not the currently active theme) + var active = null; + var disabled = []; + var primaryLightTheme = null; + var primaryDarkTheme = null; + for (var i = 0; i < document.styleSheets.length; i++) { + var ss = document.styleSheets[i]; + // The tag of each style sheet is expected to have a data-theme-name attribute + // which must contain the name of the theme. The names in localStorage much match this. + var themename = ss.ownerNode.getAttribute("data-theme-name"); + // attribute not set => non-theme stylesheet => ignore + if (themename === null) continue; + // To distinguish the default (primary) theme, it needs to have the data-theme-primary + // attribute set. + if (ss.ownerNode.getAttribute("data-theme-primary") !== null) { + primaryLightTheme = themename; + } + // Check if the theme is primary dark theme so that we could store its name in darkTheme + if (ss.ownerNode.getAttribute("data-theme-primary-dark") !== null) { + primaryDarkTheme = themename; + } + // If we find a matching theme (and it's not the default), we'll set active to non-null + if (themename === theme) active = i; + // Store the style sheets of inactive themes so that we could disable them + if (themename !== theme) disabled.push(ss); + } + var activeTheme = null; + if (active !== null) { + // If we did find an active theme, we'll (1) add the theme--$(theme) class to + document.getElementsByTagName("html")[0].className = "theme--" + theme; + activeTheme = theme; + } else { + // If we did _not_ find an active theme, then we need to fall back to the primary theme + // which can either be dark or light, depending on the user's OS preference. + var activeTheme = darkPreference ? primaryDarkTheme : primaryLightTheme; + // In case it somehow happens that the relevant primary theme was not found in the + // preceding loop, we abort without doing anything. + if (activeTheme === null) { + console.error("Unable to determine primary theme."); + return; + } + // When switching to the primary light theme, then we must not have a class name + // for the tag. That's only for non-primary or the primary dark theme. + if (darkPreference) { + document.getElementsByTagName("html")[0].className = + "theme--" + activeTheme; + } else { + document.getElementsByTagName("html")[0].className = ""; + } + } + for (var i = 0; i < document.styleSheets.length; i++) { + var ss = document.styleSheets[i]; + // The tag of each style sheet is expected to have a data-theme-name attribute + // which must contain the name of the theme. The names in localStorage much match this. + var themename = ss.ownerNode.getAttribute("data-theme-name"); + // attribute not set => non-theme stylesheet => ignore + if (themename === null) continue; + // we'll disable all the stylesheets, except for the active one + ss.disabled = !(themename == activeTheme); + } +} +set_theme_from_local_storage(); diff --git a/v0.16.12/assets/warner.js b/v0.16.12/assets/warner.js new file mode 100644 index 000000000..3f6f5d008 --- /dev/null +++ b/v0.16.12/assets/warner.js @@ -0,0 +1,52 @@ +function maybeAddWarning() { + // DOCUMENTER_NEWEST is defined in versions.js, DOCUMENTER_CURRENT_VERSION and DOCUMENTER_STABLE + // in siteinfo.js. + // If either of these are undefined something went horribly wrong, so we abort. + if ( + window.DOCUMENTER_NEWEST === undefined || + window.DOCUMENTER_CURRENT_VERSION === undefined || + window.DOCUMENTER_STABLE === undefined + ) { + return; + } + + // Current version is not a version number, so we can't tell if it's the newest version. Abort. + if (!/v(\d+\.)*\d+/.test(window.DOCUMENTER_CURRENT_VERSION)) { + return; + } + + // Current version is newest version, so no need to add a warning. + if (window.DOCUMENTER_NEWEST === window.DOCUMENTER_CURRENT_VERSION) { + return; + } + + // Add a noindex meta tag (unless one exists) so that search engines don't index this version of the docs. + if (document.body.querySelector('meta[name="robots"]') === null) { + const meta = document.createElement("meta"); + meta.name = "robots"; + meta.content = "noindex"; + + document.getElementsByTagName("head")[0].appendChild(meta); + } + + const div = document.createElement("div"); + div.classList.add("outdated-warning-overlay"); + const closer = document.createElement("button"); + closer.classList.add("outdated-warning-closer", "delete"); + closer.addEventListener("click", function () { + document.body.removeChild(div); + }); + const href = window.documenterBaseURL + "/../" + window.DOCUMENTER_STABLE; + div.innerHTML = + 'This documentation is not for the latest stable release, but for either the development version or an older release.
Click here to go to the documentation for the latest stable release.'; + div.appendChild(closer); + document.body.appendChild(div); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", maybeAddWarning); +} else { + maybeAddWarning(); +} diff --git a/v0.16.12/devdocs/style/index.html b/v0.16.12/devdocs/style/index.html new file mode 100644 index 000000000..d17f094a4 --- /dev/null +++ b/v0.16.12/devdocs/style/index.html @@ -0,0 +1,9 @@ + +Style Guide for AlgebraicJulia · Catlab.jl

Style Guide for AlgebraicJulia

The purpose of this document is to have a consistent style across AlgebraicJulia, for interests of maintainability and professionalism.

Folder structure

We follow the Julia project folder structure, where the most important elements are

  • A Project.toml file, describing dependencies and metadata.
  • A src directory. Most functionality should be implemented in this directory.
  • A test directory. Functionality implemented in src should be tested here.
  • A README.md. This should describe the purpose of the project.

Additional directories one might also use

  • A notebooks directory for explanatory notebooks.
  • A docs directory with Documenter.jl-generated docs.
  • A scripts directory with executable scripts. Note: these scripts should not contain many functions or types, they should be thin wrappers around functions from src. It is acceptable to develop some functionality in a script if that functionality is eventually migrated into src.

For most repositories in AlgebraicJulia, this should describe the top-level structure. However, some repositories might be multi-project. In that case, there is a top-level directory consisting of project directories, some of which may depend on each other.

Naming conventions

There are two ways of joining words together without spaces that are in use across AlgebraicJulia.

  1. UpperCamelCase, in which each word is capitalized, and then joined together without a separating character.

  2. lower_snake_case, in which each word is lowercase, and then joined together with underscores. The use of uppercase acronyms in lower_snake_case is tolerable but discouraged.

Occasionally, it is also acceptable to join lowercase words together without underscores, e.g., setindex! instead of set_index!; judgement about readability and consistency should be used when making the decision to use underscores or not.

Here are some example of names that are not consistent with the AlgebraicJulia style.

  • camelCase
  • UpperCamel_and_snake
  • Dashed-name

Projects

Projects should be named using UpperCamelCase with a .jl suffix, e.g. AlgebraicPetri.jl or Semagrams.jl.

Files and directories

Directories should all be lower_snake_case, except for top-level directories that are named after projects.

Library julia files and test julia files should be named with UpperCamelCase. Scripts and notebooks should be lower_snake_case.

Julia values

Modules and types should always be UpperCamelCase. Functions should always be lower_snake_case, and ideally single words. Constants should be lower_snake_case, or occasionally SCREAMING_SNAKE_CASE (judgement should be exercised about use of SCREAMING_SNAKE_CASE). Fields of structs should be lower_snake_case, or ideally lowercase single words.

Arguments to functions should have short names, often just single letters. If your function is so specific that the arguments need to be described with long argument names, consider generalizing your function. If arguments need to be longer, then lower_snake_case should be used. Additionally, you can use types and comments to document what a variable is for instead of making the names long. Some examples:

f(a_natural_number) # BAD
+f(n::Nat) # GOOD
+f(graph, vector_of_weights) # BAD
+f(g::AbstractGraph, v::AbstractVector) # GOOD

General style tips

See the official Julia style guide for general guidelines but note the following additions and exceptions:

  • Indent width is 2 spaces. For VSCode, go to settings and set Editor: Tab Size to 2.
  • Try to avoid lines longer than 80 characters. Occasionally it may be convenient to go over slightly, but never do so egregiously. To hard wrap docstrings in VSCode, the extension Rewrap adds the keybinding Alt+Q (as in Emacs).
  • Introduce a new struct when many (≥3) functions have overlapping arguments that are common aspects of a shared concept
  • Catlab uses modules more often than most Julia packages. While this may be idiosyncratic, it helps keep different components of Catlab isolated, which will be useful in the future when we spin out modules as their own packages.
  • Prefer accessor and mutator functions (e.g. dom(f)) over direct manipulation of struct fields or keys (e.g. f.dom), especially when the functions already exist. This convention supports writing generic code and makes it easier to change data structure internals without breaking existing code.
  • In long files, using comment headers can improve readability and navigability. Top-level headers and sub-headers should be formatted as:
# Section
+#########
+
+# Subsection
+#-----------

Guidelines for pull requests

Every pull request to Catlab should be reviewed by at least one person. Following are some things to check when making a PR yourself or reviewing someone else's PR. The goal of this list is to ensure that the Catlab codebase is robust and maintainable. When any of these guidelines are violated, it should be documented in a comment on the PR page.

Note: This list only includes the mechanical things. When a reviewing a PR you should always use your own judgment in asking questions and making comments about API and algorithm design. That's the hard part!

Tests and code coverage

  • Enhancements (new features) must have accompanying unit tests
  • Bug fixes should come with unit tests exposing the bug, unless producing a minimal example is unusually difficult
  • Do not delete existing unit tests, unless you have a very good reason (e.g., the relevant functionality is being moved to another package), which is documented in the PR
  • If you are adding a new module, make sure to add the test module to the test runner (test/runtests.jl or file included therein)
  • Code coverage on the Catlab repo exceeds 90% and we try to keep it that way. We do not insist on 100% coverage, which is impractical, nor do we set a hard threshold applicable to all PRs, but generally you should aim for 90%+ code coverage. Any reductions in test coverage should be justified in the PR.

Documentation

  • All exported functions, types, and constants must have docstrings
  • Docstrings should be written in complete sentences, with correct capitalization and punctuation. Likewise for comments, except for fragmentary end-of-line comments.
  • Where possible, provide citations for constructions and algorithms that you implement. This reflects good scholarly values and also aids the understanding of your code by other people.

Version control

  • Commit messages should be informative and be written in complete sentences
  • Avoid one-word commit messages like "fix" or "bug". If you need to make very simple fixes on your branch, amend a previous commit and force push.
  • Avoid repeatedly merging the main branch back into your PR branch. Instead, rebase off main and force push.

Backwards compatibility

Reflecting Catlab's dual status as a research project and a user-facing library, we want to give ourselves space to experiment while also not annoying our users and each other by needlessly breaking things.

  • Like other Julia packages, Catlab aims to follow semantic versioning
  • All else equal, it is better to make breaking changes to new APIs, especially very new ones, than old APIs
  • If you plan to make major breaking changes, please coordinate with the senior developers to ensure that it makes senses and aligns with the release schedule
diff --git a/v0.16.12/generated/graphics/composejl_wiring_diagrams.ipynb b/v0.16.12/generated/graphics/composejl_wiring_diagrams.ipynb new file mode 100644 index 000000000..16d271237 --- /dev/null +++ b/v0.16.12/generated/graphics/composejl_wiring_diagrams.ipynb @@ -0,0 +1,9209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Drawing wiring diagrams in Compose.jl\n", + "\n", + "\n", + "Catlab can draw wiring diagrams using the Julia package\n", + "[Compose.jl](https://github.com/GiovineItalia/Compose.jl).\n", + "\n", + "For best results, it is recommended to load the packages\n", + "[Convex.j](https://github.com/JuliaOpt/Convex.jl) and\n", + "[SCS.jl](https://github.com/JuliaOpt/SCS.jl). When available they are used to\n", + "optimize the layout of the outer ports." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.WiringDiagrams, Catlab.Graphics\n", + "\n", + "import Convex, SCS" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Examples" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "### Symmetric monoidal category" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.Theories\n", + "\n", + "A, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)\n", + "f, g = Hom(:f, A, B), Hom(:g, B, A);" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "To start, here are a few very simple examples." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-3.0, -2.0, 6.0, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 0.0cy), (2.0cx, 0.0cy), (2.0cx, 0.0cy), (3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 0.0cy), (-2.0cx, 0.0cy), (-2.0cx, 0.0cy), (-1.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 24.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(f)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.0, -2.0, 10.0, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (4.0cx, 0.0cy), (4.0cx, 0.0cy), (5.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, 0.0cy), (1.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 0.0cy), (-4.0cx, 0.0cy), (-4.0cx, 0.0cy), (-3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 40.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(f⋅g)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-3.0, -3.5, 6.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 1.5cy), (2.0cx, 1.5cy), (2.0cx, 1.5000006561919943cy), (3.0cx, 1.5000006561919943cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.5cy), (2.0cx, -1.5cy), (2.0cx, -1.5000006561919943cy), (3.0cx, -1.5000006561919943cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 1.5000006561919943cy), (-2.0cx, 1.5000006561919943cy), (-2.0cx, 1.5cy), (-1.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.5000006561919943cy), (-2.0cx, -1.5000006561919943cy), (-2.0cx, -1.5cy), (-1.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -2.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 24.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(f⊗g)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Here is a more complex example, involving generators with compound domains and\n", + "codomains." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-11.0, -6.5, 22.0, 13.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((9.0cx, 4.5cy), (10.0cx, 4.5cy), (10.0cx, 4.500021115986101cy), (11.0cx, 4.500021115986101cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((9.0cx, 1.5cy), (10.0cx, 1.5cy), (10.0cx, 1.5000087640178628cy), (11.0cx, 1.5000087640178628cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((9.0cx, -1.5cy), (10.0cx, -1.5cy), (10.0cx, -1.5000087640178628cy), (11.0cx, -1.5000087640178628cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((9.0cx, -4.5cy), (10.0cx, -4.5cy), (10.0cx, -4.500021115986101cy), (11.0cx, -4.500021115986101cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, -1.5cy), (-6.0cx, -1.5cy), (-6.0cx, -1.5cy), (-5.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, 1.5cy), (-6.0cx, 1.5cy), (-6.0cx, 1.5cy), (-5.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, -4.5cy), (-6.0cx, -4.5cy), (-6.0cx, -4.5cy), (-5.0cx, -4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, 4.5cy), (-6.0cx, 4.5cy), (-6.0cx, 4.5cy), (-5.0cx, 4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.5cy), (-2.0cx, -1.5cy), (-2.0cx, -1.5cy), (-1.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 1.5cy), (-2.0cx, 1.5cy), (-2.0cx, 1.5cy), (-1.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -4.5cy), (-2.0cx, -4.5cy), (-2.0cx, -4.5cy), (-1.0cx, -4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 4.5cy), (-2.0cx, 4.5cy), (-2.0cx, 4.5cy), (-1.0cx, 4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.5cy), (2.0cx, -1.5cy), (2.0cx, -1.5cy), (3.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 1.5cy), (2.0cx, 1.5cy), (2.0cx, 1.5cy), (3.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -4.5cy), (2.0cx, -4.5cy), (2.0cx, -4.5cy), (3.0cx, -4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 4.5cy), (2.0cx, 4.5cy), (2.0cx, 4.5cy), (3.0cx, 4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.0cx, -1.5cy), (6.0cx, -1.5cy), (6.0cx, -1.5cy), (7.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.0cx, 1.5cy), (6.0cx, 1.5cy), (6.0cx, 1.5cy), (7.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.0cx, -4.5cy), (6.0cx, -4.5cy), (6.0cx, -4.5cy), (7.0cx, -4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.0cx, 4.5cy), (6.0cx, 4.5cy), (6.0cx, 4.5cy), (7.0cx, 4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-11.0cx, 4.500021115986101cy), (-10.0cx, 4.500021115986101cy), (-10.0cx, 4.5cy), (-9.0cx, 4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-11.0cx, 1.5000087640178628cy), (-10.0cx, 1.5000087640178628cy), (-10.0cx, 1.5cy), (-9.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-11.0cx, -1.5000087640178628cy), (-10.0cx, -1.5000087640178628cy), (-10.0cx, -1.5cy), (-9.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-11.0cx, -4.500021115986101cy), (-10.0cx, -4.500021115986101cy), (-10.0cx, -4.5cy), (-9.0cx, -4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((7.0cx, 3.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((7.0cx, 0.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((7.0cx, -2.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"k\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((7.0cx, -5.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"h\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.5cy), (2.0cx, 5.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"m\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, -5.5cy), (2.0cx, 5.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"n\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -5.5cy), (2.0cx, 11.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"l\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 0.5cy), (2.0cx, 5.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"n\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, -5.5cy), (2.0cx, 5.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"m\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-9.0cx, 3.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"k\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-9.0cx, 0.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"h\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-9.0cx, -2.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-9.0cx, -5.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 88.0mm, 52.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " k\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " m\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " n\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " l\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " n\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " m\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " k\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " k\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " m\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " n\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " l\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " n\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " m\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " k\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "h, k = Hom(:h, C, D), Hom(:k, D, C)\n", + "m, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)\n", + "q = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)\n", + "\n", + "to_composejl((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Identities and braidings appear as wires." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-2.0, -2.0, 4.0, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (1.0cx, 0.0cy), (1.0cx, 0.0cy), (2.0cx, 0.0cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, 0.0cy), (-1.0cx, 0.0cy), (-1.0cx, 0.0cy), (0.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 16.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(id(A))" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-2.0, -3.5, 4.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (0.8749999871387909cx, -0.8749999871387909cy), (1.0cx, -1.4999999485551638cy), (2.0cx, -1.4999999485551638cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, 1.499999948555164cy), (-1.0cx, 1.499999948555164cy), (-0.8749999871387909cx, 0.8749999871387909cy), (0.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (0.8749999871387909cx, 0.8749999871387909cy), (1.0cx, 1.499999948555164cy), (2.0cx, 1.499999948555164cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, -1.4999999485551638cy), (-1.0cx, -1.4999999485551638cy), (-0.8749999871387909cx, -0.8749999871387909cy), (0.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 16.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(braid(A,B))" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.0, -3.5, 10.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (3.874999987138791cx, 0.8749999871387909cy), (4.0cx, 1.499999948555164cy), (5.0cx, 1.499999948555164cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.5cy), (2.0cx, -1.5cy), (2.125cx, -0.8749999999999998cy), (3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (3.874999987138791cx, -0.8749999871387909cy), (4.0cx, -1.4999999485551638cy), (5.0cx, -1.4999999485551638cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 1.5cy), (2.0cx, 1.5cy), (2.125cx, 0.8749999999999998cy), (3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 0.0cy), (-2.125cx, 0.8749999999999998cy), (-2.0cx, 1.5cy), (-1.0cx, 1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, -1.4999999485551638cy), (-4.0cx, -1.4999999485551638cy), (-3.874999987138791cx, -0.8749999871387909cy), (-3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 0.0cy), (-2.125cx, -0.8749999999999998cy), (-2.0cx, -1.5cy), (-1.0cx, -1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 1.499999948555164cy), (-4.0cx, 1.499999948555164cy), (-3.874999987138791cx, 0.8749999871387909cy), (-3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -2.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 40.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "The isomorphism $A \\otimes B \\otimes C \\to C \\otimes B \\otimes A$ induced by\n", + "the permutation $(3\\ 2\\ 1)$ is a composite of braidings and identities." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-4.0, -5.0, 8.0, 10.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.0cx, 3.0cy), (3.0cx, 3.0cy), (3.0cx, 3.000000254354389cy), (4.0cx, 3.000000254354389cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 1.5cy), (0.8749999999999998cx, 2.375cy), (1.0cx, 3.0cy), (2.0cx, 3.0cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, -1.5cy), (-0.7500000000000002cx, -0.2500000000000002cy), (-1.2499999999999998cx, 0.2500000000000002cy), (0.0cx, 1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.0cx, -3.000000688879835cy), (-3.0cx, -3.000000688879835cy), (-2.8750001722199587cx, -2.3750001722199587cy), (-2.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.0cx, -1.5cy), (2.8750001722199587cx, -2.3750001722199587cy), (3.0cx, -3.000000688879835cy), (4.0cx, -3.000000688879835cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 1.5cy), (1.2499999999999998cx, 0.2500000000000002cy), (0.7500000000000002cx, -0.2500000000000002cy), (2.0cx, -1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, 3.0cy), (-1.0cx, 3.0cy), (-0.8749999999999998cx, 2.375cy), (0.0cx, 1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.0cx, 3.000000254354389cy), (-3.0cx, 3.000000254354389cy), (-3.0cx, 3.0cy), (-2.0cx, 3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.0cx, -1.5cy), (2.8750001377518934cx, -0.6249998622481063cy), (3.0cx, 5.510075751738539e-7cy), (4.0cx, 5.510075751738539e-7cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, -3.0cy), (1.0cx, -3.0cy), (1.1250000000000002cx, -2.375cy), (2.0cx, -1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, -1.5cy), (-1.1250000000000002cx, -2.375cy), (-1.0cx, -3.0cy), (0.0cx, -3.0cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.0cx, 5.510075751738539e-7cy), (-3.0cx, 5.510075751738539e-7cy), (-2.8750001377518934cx, -0.6249998622481063cy), (-2.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 32.0mm, 40.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))\n", + "\n", + "to_composejl(σ)" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "By default, anchor points are added along identity and braiding wires to\n", + "reproduce the expression structure in the layout. The anchors can be disabled\n", + "to get a more \"unbiased\" layout." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-4.0, -5.0, 8.0, 10.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.0cx, -2.9999958608285895cy), (0.0cx, -2.9999958608285895cy), (0.0cx, 2.999995860828556cy), (4.0cx, 2.999995860828556cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.0cx, 2.999995860828556cy), (0.0cx, 2.999995860828556cy), (0.0cx, -2.9999958608285895cy), (4.0cx, -2.9999958608285895cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.0cx, -4.6180593879910504e-14cy), (0.0cx, -4.6180593879910504e-14cy), (0.0cx, -4.6180593879910504e-14cy), (4.0cx, -4.6180593879910504e-14cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 32.0mm, 40.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(σ, anchor_wires=false)" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "### Biproduct category" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-2.25, -3.5, 4.5, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.21650635094610968cx, 0.12499999999999999cy), (1.2767626617945311cx, 0.7371392664783356cy), (1.233253175473055cx, 1.4999998147967122cy), (2.25cx, 1.4999998147967122cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.21650635094610968cx, -0.12499999999999999cy), (1.2767626617945311cx, -0.7371392664783355cy), (1.233253175473055cx, -1.4999998147967113cy), (2.25cx, -1.4999998147967113cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.25cx, 5.88492122723702e-17cy), (-1.25cx, 5.88492122723702e-17cy), (-1.25cx, -1.5308084989341916e-16cy), (-0.25cx, -3.061616997868383e-17cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-0.25cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 18.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)\n", + "f = Hom(:f, A, B)\n", + "\n", + "to_composejl(mcopy(A))" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-2.25, -2.0, 4.5, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.25cx, 1.5528147521125472e-16cy), (-1.25cx, 1.5528147521125472e-16cy), (-1.25cx, -1.5308084989341916e-16cy), (-0.25cx, -3.061616997868383e-17cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-0.25cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 18.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(delete(A))" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.5, -3.5, 11.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.5cx, 0.0cy), (4.5cx, 0.0cy), (4.5cx, 0.0cy), (5.5cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.03349364905389cx, -0.12499999999999999cy), (-1.9732372981077804cx, -0.7371392896287466cy), (-2.016746824526945cx, -1.5cy), (-1.0cx, -1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.03349364905389cx, 0.12499999999999999cy), (-1.9732372981077804cx, 0.7371392896287466cy), (-2.016746824526945cx, 1.5cy), (-1.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.5cy), (2.016746824526945cx, -1.5cy), (1.9732372981077804cx, -0.7371392896287466cy), (3.03349364905389cx, -0.12499999999999999cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 1.5cy), (2.016746824526945cx, 1.5cy), (1.9732372981077804cx, 0.7371392896287463cy), (3.03349364905389cx, 0.12499999999999993cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.5cx, 5.88492122723702e-17cy), (-4.5cx, 5.88492122723702e-17cy), (-4.5cx, -1.5308084989341916e-16cy), (-3.5cx, -3.061616997868383e-17cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -2.5cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.5cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 44.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(mcopy(A)⋅(f⊗f)⋅mmerge(B))" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-6.5, -3.25, 13.0, 6.5, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.875cx, -0.7834936490538904cy), (-1.4548480126628813cx, 1.6762817474839113cy), (1.4999999665292176cx, 1.2332531754730547cy), (1.4999999665292176cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.875cx, -0.7834936490538903cy), (1.4548480126628798cx, 1.676281747483916cy), (-1.4999999665292392cx, 1.2332531754730547cy), (-1.4999999665292392cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.125cx, -0.7834936490538903cy), (-4.170151989517864cx, 1.0267626984227447cy), (-4.499999983975182cx, 1.2332531754730547cy), (-4.499999983975182cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.125cx, -0.7834936490538904cy), (4.170151989517863cx, 1.026762698422742cy), (4.499999983975171cx, 1.2332531754730547cy), (4.499999983975171cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.000108401535956cx, -3.25cy), (3.000108401535956cx, -2.25cy), (3.0cx, -2.25cy), (3.0cx, -1.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.000108401535958cx, -3.25cy), (-3.000108401535958cx, -2.25cy), (-3.0cx, -2.25cy), (-3.0cx, -1.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.75cx, -1.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.25cx, -1.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 52.0mm, 26.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(mcopy(A⊗B), orientation=TopToBottom)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-9.5, -3.25, 19.0, 6.5, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-0.12499999999999994cx, -0.7834936490538903cy), (-1.5452067091487423cx, 1.6763765284419279cy), (-4.500437741022215cx, 1.2332531754730547cy), (-4.500437741022215cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((6.125cx, -0.7834936490538904cy), (7.170134912149241cx, 1.0267331195526297cy), (7.499863365026198cx, 1.2332531754730547cy), (7.499863365026198cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.875cx, -0.7834936490538904cy), (-4.0798550431450495cx, 2.325788623169923cy), (1.4999437226718668cx, 1.2332531754730547cy), (1.4999437226718668cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.12500000000000003cx, -0.7834936490538904cy), (1.5452067091487474cx, 1.6763765284419347cy), (4.500437741022248cx, 1.2332531754730547cy), (4.500437741022248cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-6.125cx, -0.7834936490538903cy), (-7.170134912149241cx, 1.0267331195526297cy), (-7.499863365026196cx, 1.2332531754730547cy), (-7.499863365026196cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.875cx, -0.7834936490538903cy), (4.079855043145008cx, 2.3257886231699985cy), (-1.4999437226722208cx, 1.2332531754730547cy), (-1.4999437226722208cx, 3.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((6.0000074841964945cx, -3.25cy), (6.0000074841964945cx, -2.25cy), (6.0cx, -2.25cy), (6.0cx, -1.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.3617227282138419e-15cx, -3.25cy), (-1.3617227282138419e-15cx, -2.25cy), (7.654042494670958e-17cx, -2.25cy), (1.5308084989341915e-17cx, -1.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-6.0000074841964945cx, -3.25cy), (-6.0000074841964945cx, -2.25cy), (-6.0cx, -2.25cy), (-6.0cx, -1.25cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.75cx, -1.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-0.25cx, -1.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-6.25cx, -1.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 76.0mm, 26.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(mcopy(A⊗B⊗C), orientation=TopToBottom)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "### Compact closed category" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The unit and co-unit of a compact closed category appear as caps and cups." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-2.0, -3.5, 4.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (4.592425339298191e-17cx, 0.7499999742775821cy), (1.0cx, 1.499999948555164cy), (2.0cx, 1.499999948555164cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (4.5924253392981905e-17cx, -0.749999974277582cy), (1.0cx, -1.4999999485551638cy), (2.0cx, -1.4999999485551638cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (0.0cx, 0.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 16.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "A, B = Ob(FreeCompactClosedCategory, :A, :B)\n", + "\n", + "to_composejl(dunit(A))" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-2.0, -3.5, 4.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, 1.499999948555164cy), (-1.0cx, 1.499999948555164cy), (-1.3777276017894574e-16cx, 0.7499999742775822cy), (0.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.0cx, -1.4999999485551638cy), (-1.0cx, -1.4999999485551638cy), (4.592425339298189e-17cx, -0.7499999742775818cy), (0.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 0.0cy), (0.0cx, 0.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 16.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(dcounit(A))" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "cell_type": "markdown", + "source": [ + "In a self-dual compact closed category, such as a bicategory of relations,\n", + "every morphism $f: A \\to B$ has a transpose $f^\\dagger: B \\to A$ given by\n", + "bending wires:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.0, -5.0, 10.0, 10.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, -3.0cy), (4.0cx, -3.0cy), (4.0cx, -3.000201264130896cy), (5.0cx, -3.000201264130896cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, -3.0cy), (1.5cx, -3.0cy), (1.5cx, -3.0cy), (3.0cx, -3.0cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.5cy), (-3.0cx, -2.25cy), (-1.5cx, -3.0cy), (0.0cx, -3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 0.0cy), (2.0cx, 0.0cy), (3.0cx, 0.7500000000000001cy), (3.0cx, 1.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.5cy), (-3.0cx, -0.7499999999999999cy), (-2.0cx, 0.0cy), (-1.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 3.0cy), (1.5cx, 3.0cy), (3.0cx, 2.25cy), (3.0cx, 1.5cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 3.0cy), (-1.5cx, 3.0cy), (-1.5cx, 3.0cy), (0.0cx, 3.0cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 3.0002012641308937cy), (-4.0cx, 3.0002012641308937cy), (-4.0cx, 3.0cy), (-3.0cx, 3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 1.5cy), (0.0cx, 0.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.5cy), (0.0cx, 0.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 40.0mm, 40.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "A, B = Ob(FreeBicategoryRelations, :A, :B)\n", + "f = Hom(:f, A, B)\n", + "\n", + "to_composejl((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))" + ], + "metadata": {}, + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "### Abelian bicategory of relations" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "In an abelian bicategory of relations, such as the category of linear\n", + "relations, the duplication morphisms $\\Delta_X: X \\to X \\oplus X$ and addition\n", + "morphisms $\\blacktriangledown_X: X \\oplus X \\to X$ belong to a bimonoid. Among\n", + "other things, this means that the following two morphisms are equal." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-3.5, -3.5, 7.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.4665063509461096cx, 0.12499999999999999cy), (2.5267626617945314cx, 0.7371392664783357cy), (2.4832531754730547cx, 1.4999998147967122cy), (3.5cx, 1.4999998147967122cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.4665063509461096cx, -0.12499999999999999cy), (2.526762661794531cx, -0.7371392664783356cy), (2.4832531754730547cx, -1.4999998147967113cy), (3.5cx, -1.4999998147967113cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, -1.5308084989341916e-16cy), (1.0cx, -3.061616997868383e-17cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.5cx, 1.4999998147967122cy), (-2.483253175473055cx, 1.4999998147967122cy), (-2.526762661794532cx, 0.7371392664783353cy), (-1.4665063509461098cx, 0.12499999999999993cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.5cx, -1.4999998147967113cy), (-2.4832531754730547cx, -1.4999998147967113cy), (-2.526762661794531cx, -0.7371392664783356cy), (-1.4665063509461096cx, -0.12499999999999999cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.5cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 28.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ], + "cell_type": "code", + "source": [ + "X = Ob(FreeAbelianBicategoryRelations, :X)\n", + "\n", + "to_composejl(plus(X) ⋅ mcopy(X))" + ], + "metadata": {}, + "execution_count": 20 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-4.5, -6.5, 9.0, 13.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.5cx, 3.0cy), (3.5cx, 3.0cy), (3.5cx, 3.000108401535956cy), (4.5cx, 3.000108401535956cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.5cx, -3.0cy), (3.5cx, -3.0cy), (3.5cx, -3.000108401535958cy), (4.5cx, -3.000108401535958cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.03349364905389cx, 2.875cy), (0.7365381056766584cx, 1.2757214207425067cy), (-0.7365381056766584cx, -1.2757214207425076cy), (2.03349364905389cx, -2.875cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.03349364905389cx, -2.875cy), (0.7365381056766584cx, -1.2757214207425067cy), (-0.7365381056766584cx, 1.2757214207425067cy), (2.03349364905389cx, 2.875cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, -4.5cy), (1.016746824526945cx, -4.5cy), (0.9732372981077804cx, -3.7371392896287468cy), (2.03349364905389cx, -3.125cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.03349364905389cx, -3.125cy), (-0.9732372981077804cx, -3.7371392896287468cy), (-1.016746824526945cx, -4.5cy), (0.0cx, -4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((0.0cx, 4.5cy), (1.016746824526945cx, 4.5cy), (0.9732372981077804cx, 3.7371392896287463cy), (2.03349364905389cx, 3.125cy))], Symbol(\"\")), Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.03349364905389cx, 3.125cy), (-0.9732372981077804cx, 3.7371392896287468cy), (-1.016746824526945cx, 4.5cy), (0.0cx, 4.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.5cx, 3.000108401535956cy), (-3.5cx, 3.000108401535956cy), (-3.5cx, 3.0cy), (-2.5cx, 3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-4.5cx, -3.000108401535958cy), (-3.5cx, -3.000108401535958cy), (-3.5cx, -3.0cy), (-2.5cx, -3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.0cx, 2.75cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((2.0cx, -3.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.5cx, 2.75cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-2.5cx, -3.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 36.0mm, 52.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ], + "cell_type": "code", + "source": [ + "to_composejl((mcopy(X)⊕mcopy(X)) ⋅ (id(X)⊕swap(X,X)⊕id(X)) ⋅ (plus(X)⊕plus(X)))" + ], + "metadata": {}, + "execution_count": 21 + }, + { + "cell_type": "markdown", + "source": [ + "## Custom styles" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The visual appearance of wiring diagrams can be customized by passing Compose\n", + "[properties](http://giovineitalia.github.io/Compose.jl/latest/gallery/properties/)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.0, -2.0, 10.0, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (4.0cx, 0.0cy), (4.0cx, 0.0cy), (5.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, 0.0cy), (1.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 0.0cy), (-4.0cx, 0.0cy), (-4.0cx, 0.0cy), (-3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))]), Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.9019607843137255,0.9019607843137255,0.9803921568627451,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))]), Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.9019607843137255,0.9019607843137255,0.9803921568627451,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 40.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 22 + } + ], + "cell_type": "code", + "source": [ + "using Compose: fill, stroke\n", + "\n", + "A, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)\n", + "f, g = Hom(:f, A, B), Hom(:g, B, A)\n", + "\n", + "to_composejl(f⋅g, props=Dict(\n", + " :box => [fill(\"lavender\"), stroke(\"black\")],\n", + "))" + ], + "metadata": {}, + "execution_count": 22 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-3.5, -3.5, 7.0, 7.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.4665063509461096cx, 0.12499999999999999cy), (2.5267626617945314cx, 0.7371392664783357cy), (2.4832531754730547cx, 1.4999998147967122cy), (3.5cx, 1.4999998147967122cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.4665063509461096cx, -0.12499999999999999cy), (2.526762661794531cx, -0.7371392664783356cy), (2.4832531754730547cx, -1.4999998147967113cy), (3.5cx, -1.4999998147967113cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, -1.5308084989341916e-16cy), (1.0cx, -3.061616997868383e-17cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.5cx, 1.4999998147967122cy), (-2.483253175473055cx, 1.4999998147967122cy), (-2.526762661794532cx, 0.7371392664783353cy), (-1.4665063509461098cx, 0.12499999999999993cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.5cx, -1.4999998147967113cy), (-2.4832531754730547cx, -1.4999998147967113cy), (-2.526762661794531cx, -0.7371392664783356cy), (-1.4665063509461096cx, -0.12499999999999999cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))]), Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(1.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.5cx, -0.25cy), (0.5cx, 0.5cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))]), Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,1.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 28.0mm, 28.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ], + "cell_type": "code", + "source": [ + "X = Ob(FreeAbelianBicategoryRelations, :X)\n", + "\n", + "to_composejl(plus(X) ⋅ mcopy(X), props=Dict(\n", + " :junction => [fill(\"red\"), stroke(\"black\")],\n", + " :variant_junction => [fill(\"blue\"), stroke(\"black\")],\n", + "))" + ], + "metadata": {}, + "execution_count": 23 + }, + { + "cell_type": "markdown", + "source": [ + "The background color can also be changed." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}((0.0w, 0.0h), 1.0w, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.8274509803921568,0.8274509803921568,0.8274509803921568,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.0, -2.0, 10.0, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (4.0cx, 0.0cy), (4.0cx, 0.0cy), (5.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, 0.0cy), (1.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 0.0cy), (-4.0cx, 0.0cy), (-4.0cx, 0.0cy), (-3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))]), Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(1.0,1.0,1.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))]), Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(1.0,1.0,1.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), 40.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 24 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(f⋅g, background_color=\"lightgray\", props=Dict(\n", + " :box => [fill(\"white\"), stroke(\"black\")],\n", + "))" + ], + "metadata": {}, + "execution_count": 24 + }, + { + "cell_type": "markdown", + "source": [ + "By default, the boxes are rectangular (`:rectangle`). Other available shapes\n", + "include circles (`:circle`) and ellipses (`:ellipse`)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-5.0, -2.0, 10.0, 4.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (4.0cx, 0.0cy), (4.0cx, 0.0cy), (5.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, -2.4492935982947064e-16cy), (1.0cx, -1.2246467991473532e-16cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, -9.705092055532417e-17cy), (-4.0cx, -9.705092055532417e-17cy), (-4.0cx, -2.4492935982947064e-16cy), (-3.0cx, -1.2246467991473532e-16cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}}(Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}[Compose.CirclePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Measures.Length{:w, Float64}}((0.5w, 0.5h), 0.5w)], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 40.0mm, 16.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 25 + } + ], + "cell_type": "code", + "source": [ + "to_composejl(f⋅g, default_box_shape=:circle)" + ], + "metadata": {}, + "execution_count": 25 + }, + { + "cell_type": "markdown", + "source": [ + "## Output formats" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The function `to_composejl` returns a `ComposePicture` object, which contains\n", + "a Compose.jl context as well as a recommended width and height. When displayed\n", + "interactively, this object is rendered using Compose's SVG backend." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Any backend can be used by calling Compose's `draw` function. The SVG and\n", + "[PGF](https://ctan.org/pkg/pgf) (LaTeX) backends are always available. To use\n", + "the PNG or PDF backends, the extra packages\n", + "[Cairo.jl](https://github.com/JuliaGraphics/Cairo.jl) and\n", + "[Fontconfig.jl](https://github.com/JuliaGraphics/Fontconfig.jl) must be\n", + "installed." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "For example, here is how to use the PGF backend." + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\begin{tikzpicture}[x=1mm,y=-1mm]\n", + "\\definecolor{mycolor000000}{rgb}{0,0,0}\n", + "\\begin{scope}\n", + "\\path [fill=mycolor000000,draw=mycolor000000] (32,8) .. controls (36,8) and (36,8) .. (40,8);\n", + "\\end{scope}\n", + "\\begin{scope}\n", + "\\path [fill=mycolor000000,draw=mycolor000000] (16,8) .. controls (20,8) and (20,8) .. (24,8);\n", + "\\end{scope}\n", + "\\begin{scope}\n", + "\\path [fill=mycolor000000,draw=mycolor000000] (0,8) .. controls (4,8) and (4,8) .. (8,8);\n", + "\\end{scope}\n", + "\\begin{scope}\n", + "\\path [fill=mycolor000000,fill opacity=0,draw=mycolor000000] (24,4) rectangle +(8,8);\n", + "\\end{scope}\n", + "\\begin{scope}\n", + "\\draw (28,8) node [text=mycolor000000,rotate around={-0: (0,0)},inner sep=0.0]{\\fontsize{12mm}{14.4mm}\\selectfont $\\text{g}$};\n", + "\\end{scope}\n", + "\\begin{scope}\n", + "\\path [fill=mycolor000000,fill opacity=0,draw=mycolor000000] (8,4) rectangle +(8,8);\n", + "\\end{scope}\n", + "\\begin{scope}\n", + "\\draw (12,8) node [text=mycolor000000,rotate around={-0: (0,0)},inner sep=0.0]{\\fontsize{12mm}{14.4mm}\\selectfont $\\text{f}$};\n", + "\\end{scope}\n", + "\\end{tikzpicture}\n", + "\n" + ] + } + ], + "cell_type": "code", + "source": [ + "using Compose: draw, PGF\n", + "\n", + "pic = to_composejl(f⋅g, rounded_boxes=false)\n", + "pgf = sprint() do io\n", + " pgf_backend = PGF(io, pic.width, pic.height,\n", + " false, # emit_on_finish\n", + " true, # only_tikz\n", + " texfonts=true)\n", + " draw(pgf_backend, pic.context)\n", + "end\n", + "println(pgf)" + ], + "metadata": {}, + "execution_count": 26 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphics/composejl_wiring_diagrams/81ad47fa.svg b/v0.16.12/generated/graphics/composejl_wiring_diagrams/81ad47fa.svg new file mode 100644 index 000000000..ccfe4bd2f --- /dev/null +++ b/v0.16.12/generated/graphics/composejl_wiring_diagrams/81ad47fa.svg @@ -0,0 +1,825 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + diff --git a/v0.16.12/generated/graphics/composejl_wiring_diagrams/index.html b/v0.16.12/generated/graphics/composejl_wiring_diagrams/index.html new file mode 100644 index 000000000..525becd39 --- /dev/null +++ b/v0.16.12/generated/graphics/composejl_wiring_diagrams/index.html @@ -0,0 +1,1754 @@ + +Drawing wiring diagrams in Compose.jl · Catlab.jl

Drawing wiring diagrams in Compose.jl

Catlab can draw wiring diagrams using the Julia package Compose.jl.

For best results, it is recommended to load the packages Convex.j and SCS.jl. When available they are used to optimize the layout of the outer ports.

using Catlab.WiringDiagrams, Catlab.Graphics
+
+import Convex, SCS

Examples

Symmetric monoidal category

using Catlab.Theories
+
+A, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)
+f, g = Hom(:f, A, B), Hom(:g, B, A);

To start, here are a few very simple examples.

to_composejl(f)
to_composejl(f⋅g)
to_composejl(f⊗g)

Here is a more complex example, involving generators with compound domains and codomains.

h, k = Hom(:h, C, D),  Hom(:k, D, C)
+m, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)
+q = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)
+
+to_composejl((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))
Example block output

Identities and braidings appear as wires.

to_composejl(id(A))
to_composejl(braid(A,B))
to_composejl(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))

The isomorphism $A \otimes B \otimes C \to C \otimes B \otimes A$ induced by the permutation $(3\ 2\ 1)$ is a composite of braidings and identities.

σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))
+
+to_composejl(σ)

By default, anchor points are added along identity and braiding wires to reproduce the expression structure in the layout. The anchors can be disabled to get a more "unbiased" layout.

to_composejl(σ, anchor_wires=false)

Biproduct category

A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)
+f = Hom(:f, A, B)
+
+to_composejl(mcopy(A))
to_composejl(delete(A))
to_composejl(mcopy(A)⋅(f⊗f)⋅mmerge(B))
to_composejl(mcopy(A⊗B), orientation=TopToBottom)
to_composejl(mcopy(A⊗B⊗C), orientation=TopToBottom)

Compact closed category

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

A, B = Ob(FreeCompactClosedCategory, :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:

A, B = Ob(FreeBicategoryRelations, :A, :B)
+f = Hom(:f, A, B)
+
+to_composejl((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))

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 \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)⊕swap(X,X)⊕id(X)) ⋅ (plus(X)⊕plus(X)))

Custom styles

The visual appearance of wiring diagrams can be customized by passing Compose 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, props=Dict(
+  :box => [fill("lavender"), stroke("black")],
+))
X = Ob(FreeAbelianBicategoryRelations, :X)
+
+to_composejl(plus(X) ⋅ mcopy(X), props=Dict(
+  :junction => [fill("red"), stroke("black")],
+  :variant_junction => [fill("blue"), stroke("black")],
+))

The background color can also be changed.

to_composejl(f⋅g, background_color="lightgray", props=Dict(
+  :box => [fill("white"), stroke("black")],
+))

By default, the boxes are rectangular (:rectangle). Other available shapes include circles (:circle) and ellipses (:ellipse).

to_composejl(f⋅g, default_box_shape=:circle)

Output formats

The function to_composejl returns a ComposePicture object, which contains a Compose.jl context as well as a recommended width and height. When displayed interactively, this object is rendered using Compose's SVG backend.

Any backend can be used by calling Compose's draw function. The SVG and PGF (LaTeX) backends are always available. To use the PNG or PDF backends, the extra packages Cairo.jl and Fontconfig.jl must be installed.

For example, here is how to use the PGF backend.

using Compose: draw, PGF
+
+pic = to_composejl(f⋅g, rounded_boxes=false)
+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)
\begin{tikzpicture}[x=1mm,y=-1mm]
+\definecolor{mycolor000000}{rgb}{0,0,0}
+\begin{scope}
+\path [fill=mycolor000000,draw=mycolor000000] (32,8) .. controls (36,8) and (36,8) .. (40,8);
+\end{scope}
+\begin{scope}
+\path [fill=mycolor000000,draw=mycolor000000] (16,8) .. controls (20,8) and (20,8) .. (24,8);
+\end{scope}
+\begin{scope}
+\path [fill=mycolor000000,draw=mycolor000000] (0,8) .. controls (4,8) and (4,8) .. (8,8);
+\end{scope}
+\begin{scope}
+\path [fill=mycolor000000,fill opacity=0,draw=mycolor000000] (24,4) rectangle +(8,8);
+\end{scope}
+\begin{scope}
+\draw (28,8) node [text=mycolor000000,rotate around={-0: (0,0)},inner sep=0.0]{\fontsize{12mm}{14.4mm}\selectfont $\text{g}$};
+\end{scope}
+\begin{scope}
+\path [fill=mycolor000000,fill opacity=0,draw=mycolor000000] (8,4) rectangle +(8,8);
+\end{scope}
+\begin{scope}
+\draw (12,8) node [text=mycolor000000,rotate around={-0: (0,0)},inner sep=0.0]{\fontsize{12mm}{14.4mm}\selectfont $\text{f}$};
+\end{scope}
+\end{tikzpicture}
diff --git a/v0.16.12/generated/graphics/graphviz_graphs.ipynb b/v0.16.12/generated/graphics/graphviz_graphs.ipynb new file mode 100644 index 000000000..d56bd4082 --- /dev/null +++ b/v0.16.12/generated/graphics/graphviz_graphs.ipynb @@ -0,0 +1,1042 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Drawing graphs in Graphviz\n", + "\n", + "\n", + "All of the basic graph types provided by the Catlab `Graphs` module can be\n", + "drawn using [Graphviz](https://www.graphviz.org/). By default, \"directed\"\n", + "graph types (`Graph`, `ReflexiveGraph`) are drawn using the `dot` program and\n", + "\"undirected\" graph types (`SymmetricGraph`, `HalfEdgeGraph`) are drawn using\n", + "the `neato` program." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.Graphs, Catlab.Graphics" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Drawing basic graphs" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "g = cycle_graph(Graph, 3)\n", + "to_graphviz(g)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1--n2\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2--n3\n", + "\n", + "\n", + "\n", + "\n", + "n3--n1\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "sg = cycle_graph(SymmetricGraph, 3)\n", + "to_graphviz(sg)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Node and edge IDs can be shown by setting `node_labels=true` and\n", + "`edge_labels=true`, or a data attribute can be used as a label by setting\n", + "`node_labels=:my_vertex_attr` and `edge_lables=:my_edge_attr`." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(g, node_labels=true, edge_labels=true)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "Graph-level, node-level, and edge-level [Graphviz\n", + "attributes](https://graphviz.org/doc/info/attrs.html) can be supplied using\n", + "the `graph_attrs`, `node_attrs`, and `edge_attrs` keyword arguments." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :style => \"dotted\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(g, node_attrs=Dict(:color => \"cornflowerblue\"),\n", + " edge_attrs=Dict(:style => \"dotted\"))" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "## Drawing graph homomorphisms\n", + "\n", + "Graph homomorphsims (`ACSetTransformation`s between graphs) can also be drawn\n", + "using Graphviz, in several different styles." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ACSetTransformation((V = FinFunction([1, 2, 1, 2], 4, 2), E = FinFunction([1, 2, 1, 2], 4, 2)), Graph {V:4, E:4}, Graph {V:2, E:2})" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.CategoricalAlgebra\n", + "\n", + "f = homomorphism(cycle_graph(Graph, 4), complete_graph(Graph, 2))" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "By default, the domain and codomain graph are both drawn, as well the vertex\n", + "mapping between them." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"cluster_dom\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Subgraph(\"cluster_cod\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"cod_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"cod_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"cod_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"cod_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"cod_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"cod_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_1\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_1\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_2\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_2\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_3\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_1\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_4\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_2\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "cluster_dom\n", + "\n", + "\n", + "\n", + "cluster_cod\n", + "\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_1\n", + "\n", + "\n", + "\n", + "\n", + "dom_1->cod_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_2\n", + "\n", + "\n", + "\n", + "\n", + "dom_2->cod_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_3->cod_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4->dom_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4->cod_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_1->cod_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_2->cod_1\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(f)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "To see the edge mapping, which is not necessarily unique in the presence of\n", + "the multiple edges, colors can be used." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"cluster_dom\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Subgraph(\"cluster_cod\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"cod_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"cod_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"cod_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"cod_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"cod_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"cod_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_1\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_1\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_2\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_2\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_3\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_1\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"\\\"dom_4\\\"\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"\\\"cod_2\\\"\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\", :style => \"dotted\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "cluster_dom\n", + "\n", + "\n", + "\n", + "cluster_cod\n", + "\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_1\n", + "\n", + "\n", + "\n", + "\n", + "dom_1->cod_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_2\n", + "\n", + "\n", + "\n", + "\n", + "dom_2->cod_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_3->cod_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4->dom_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4->cod_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_1->cod_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cod_2->cod_1\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(f, edge_colors=true)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "Alternatively, the graph homomorphism can be depicted by drawing only the\n", + "domain graph and coloring its nodes and edges. By default, setting\n", + "`draw_codom=false` sets both `node_colors=true` and `edge_colors=true`." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4->dom_1\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(f, draw_codom=false)" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "dom_4->dom_1\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(f, draw_codom=false, edge_colors=false)" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "## Drawing maps between finite sets\n", + "\n", + "It is also possible to visualize maps between finite sets (`FinFunction`s\n", + "between `FinSet`s) using Graphviz." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"bipartite_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"cluster_nodes1\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n1_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n1_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n1_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"same\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Subgraph(\"cluster_nodes2\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n2_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"same\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\", :splines => \"false\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "bipartite_graph\n", + "\n", + "\n", + "cluster_nodes1\n", + "\n", + "\n", + "\n", + "cluster_nodes2\n", + "\n", + "\n", + "\n", + "\n", + "n1_1\n", + "\n", + "\n", + "\n", + "\n", + "n1_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2_1\n", + "\n", + "\n", + "\n", + "\n", + "n1_1->n2_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2_3\n", + "\n", + "\n", + "\n", + "\n", + "n1_2->n2_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1_4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2_2\n", + "\n", + "\n", + "\n", + "\n", + "n1_3->n2_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1_4->n2_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.CategoricalAlgebra.FinSets\n", + "\n", + "A = FinSet(4)\n", + "B = FinSet(3)\n", + "f = FinFunction([1,3,2,2], A, B)\n", + "\n", + "to_graphviz(f, graph_attrs=Dict(:splines=>\"false\"))" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"bipartite_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"cluster_nodes1\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n1_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n1_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n1_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"same\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Subgraph(\"cluster_nodes2\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n2_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n2_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"same\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:constraint => \"false\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"TB\", :splines => \"false\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "bipartite_graph\n", + "\n", + "\n", + "cluster_nodes1\n", + "\n", + "\n", + "\n", + "cluster_nodes2\n", + "\n", + "\n", + "\n", + "\n", + "n1_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n1_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "\n", + "n2_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n1_1->n2_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "\n", + "n2_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1_2->n2_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1_4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "\n", + "n2_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1_3->n2_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1_4->n2_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(f, node_labels=true,\n", + " graph_attrs=Dict(:splines=>\"false\", :rankdir => \"TB\"))" + ], + "metadata": {}, + "execution_count": 12 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphics/graphviz_graphs/index.html b/v0.16.12/generated/graphics/graphviz_graphs/index.html new file mode 100644 index 000000000..9dee7ca69 --- /dev/null +++ b/v0.16.12/generated/graphics/graphviz_graphs/index.html @@ -0,0 +1,714 @@ + +Drawing graphs in Graphviz · Catlab.jl

Drawing graphs in Graphviz

All of the basic graph types provided by the Catlab Graphs module can be drawn using Graphviz. By default, "directed" graph types (Graph, ReflexiveGraph) are drawn using the dot program and "undirected" graph types (SymmetricGraph, HalfEdgeGraph) are drawn using the neato program.

using Catlab.Graphs, Catlab.Graphics

Drawing basic graphs

g = cycle_graph(Graph, 3)
+to_graphviz(g)
sg = cycle_graph(SymmetricGraph, 3)
+to_graphviz(sg)

Node and edge IDs can be shown by setting node_labels=true and edge_labels=true, or a data attribute can be used as a label by setting node_labels=:my_vertex_attr and edge_lables=:my_edge_attr.

to_graphviz(g, node_labels=true, edge_labels=true)

Graph-level, node-level, and edge-level Graphviz attributes can be supplied using the graph_attrs, node_attrs, and edge_attrs keyword arguments.

to_graphviz(g, node_attrs=Dict(:color => "cornflowerblue"),
+            edge_attrs=Dict(:style => "dotted"))

Drawing graph homomorphisms

Graph homomorphsims (ACSetTransformations between graphs) can also be drawn using Graphviz, in several different styles.

using Catlab.CategoricalAlgebra
+
+f = homomorphism(cycle_graph(Graph, 4), complete_graph(Graph, 2))
ACSetTransformation((V = FinFunction([1, 2, 1, 2], 4, 2), E = FinFunction([1, 2, 1, 2], 4, 2)), Graph {V:4, E:4}, Graph {V:2, E:2})

By default, the domain and codomain graph are both drawn, as well the vertex mapping between them.

to_graphviz(f)

To see the edge mapping, which is not necessarily unique in the presence of the multiple edges, colors can be used.

to_graphviz(f, edge_colors=true)

Alternatively, the graph homomorphism can be depicted by drawing only the domain graph and coloring its nodes and edges. By default, setting draw_codom=false sets both node_colors=true and edge_colors=true.

to_graphviz(f, draw_codom=false)
to_graphviz(f, draw_codom=false, edge_colors=false)

Drawing maps between finite sets

It is also possible to visualize maps between finite sets (FinFunctions between FinSets) using Graphviz.

using Catlab.CategoricalAlgebra.FinSets
+
+A = FinSet(4)
+B = FinSet(3)
+f = FinFunction([1,3,2,2], A, B)
+
+to_graphviz(f, graph_attrs=Dict(:splines=>"false"))
to_graphviz(f, node_labels=true,
+            graph_attrs=Dict(:splines=>"false", :rankdir => "TB"))
diff --git a/v0.16.12/generated/graphics/graphviz_wiring_diagrams.ipynb b/v0.16.12/generated/graphics/graphviz_wiring_diagrams.ipynb new file mode 100644 index 000000000..af7bd8581 --- /dev/null +++ b/v0.16.12/generated/graphics/graphviz_wiring_diagrams.ipynb @@ -0,0 +1,2202 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Drawing wiring diagrams in Graphviz\n", + "\n", + "\n", + "Catlab can draw wiring diagrams using [Graphviz](https://www.graphviz.org/).\n", + "Directed wiring diagrams are drawn using the `dot` program and undirected\n", + "wiring diagrams using `neato` and `fdp`. This feature requires that Graphviz\n", + "be installed, but does not require any additional Julia packages." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.WiringDiagrams, Catlab.Graphics" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Directed wiring diagrams" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "### Symmetric monoidal category" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.Theories\n", + "\n", + "A, B = Ob(FreeSymmetricMonoidalCategory, :A, :B)\n", + "f = Hom(:f, A, B)\n", + "g = Hom(:g, B, A)\n", + "h = Hom(:h, otimes(A,B), otimes(A,B));" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "To start, here are a few very simple examples." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(f)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(compose(f,g))" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:s->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(otimes(f,g))" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "In the next example, notice how Graphviz automatically \"untwists\" the double\n", + "braiding to minimize edge crossings." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(compose(braid(A,A), otimes(f,f), braid(B,B)))" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Here is a larger composite morphism." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n5\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out2\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in2\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e8\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:s->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n3:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n3:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n3:s->n4:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n3:s->n5:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5:s->n0out2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "composite = compose(otimes(g,f), h, otimes(f,g))\n", + "to_graphviz(composite)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "By default, the wiring diagram is laid out from top to bottom. Other layout\n", + "orientations can be requested, such as left-to-right or bottom-to-top:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n5\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e8\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n4:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n5:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5:e->n0out2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(composite, orientation=LeftToRight)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n5\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"n\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"s\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"n\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"s\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out2\", \"n\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"in1\", \"s\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"n\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"s\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"n\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in2\", \"s\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"n\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"s\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"n\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"s\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"out1\", \"n\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"s\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e8\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"BT\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:n->n1:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:n->n2:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n1:n->n3:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:n->n3:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n3:n->n4:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n3:n->n5:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4:n->n0out1:s\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5:n->n0out2:s\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(composite, orientation=BottomToTop)" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "When working with very large diagrams (larger than the ones shown here), it is\n", + "sometimes convenient to omit the ports of the outer box and any wires attached\n", + "to them." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n5\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out2\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in2\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n3:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n3:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n3:s->n4:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n3:s->n5:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(composite, outer_ports=false)" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "### Biproduct category" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "A, B = Ob(FreeBiproductCategory, :A, :B)\n", + "f = Hom(:f, A, B)\n", + "g = Hom(:g, B, A);" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "By default, copies and merges are drawn the way they are represented\n", + "internally, as multiple wires." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "f1 = compose(mcopy(A), otimes(f,f))\n", + "to_graphviz(f1)" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "f2 = compose(mcopy(A), otimes(f,f), mmerge(B))\n", + "to_graphviz(f2)" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "To draw nodes for copies and merges, we need to add junctions to the wiring\n", + "diagram." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(add_junctions!(to_wiring_diagram(f1)))" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n4\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3->n2:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(add_junctions!(to_wiring_diagram(f2)))" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "### Traced monoidal category" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in2\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out2\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n0out1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n1:n\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "A, B, X, Y = Ob(FreeTracedMonoidalCategory, :A, :B, :X, :Y)\n", + "f = Hom(:f, otimes(X,A), otimes(X,B))\n", + "\n", + "to_graphviz(trace(X, A, B, f))" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(trace(X, A, B, f), orientation=LeftToRight)" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "g, h = Hom(:g, A, A), Hom(:h, B, B)\n", + "\n", + "trace_naturality = trace(X, A, B, compose(otimes(id(X),g), f, otimes(id(X),h)))\n", + "to_graphviz(trace_naturality, orientation=LeftToRight)" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "cell_type": "markdown", + "source": [ + "## Undirected wiring diagrams" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The composite of two binary relations:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\", :label => \"R\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\", :label => \"S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer1\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer2\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction2\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "R\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n1--n5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n1--n6\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "S\n", + "\n", + "\n", + "\n", + "n2--n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n2--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3--n5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4--n7\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Programs: @relation\n", + "\n", + "diagram = @relation (x,z) where (x,y,z) begin\n", + " R(x,y)\n", + " S(y,z)\n", + "end\n", + "to_graphviz(diagram, box_labels=:name)" + ], + "metadata": {}, + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "A \"wheel\"-shaped composition of relations:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\", :label => \"R\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\", :label => \"S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box3\", :label => \"T\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer1\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer2\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer3\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction2\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction4\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "R\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n1--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n1--n8\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "S\n", + "\n", + "\n", + "\n", + "n2--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "\n", + "\n", + "\n", + "n2--n9\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "T\n", + "\n", + "\n", + "\n", + "n3--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "\n", + "\n", + "\n", + "n3--n10\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4--n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5--n9\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n6--n10\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ], + "cell_type": "code", + "source": [ + "diagram = @relation (x,y,z) where (w,x,y,z) begin\n", + " R(x,w)\n", + " S(y,w)\n", + " T(z,w)\n", + "end\n", + "to_graphviz(diagram, box_labels=:name)" + ], + "metadata": {}, + "execution_count": 20 + }, + { + "cell_type": "markdown", + "source": [ + "As these examples show, the `box_labels` keyword argument specifies the data\n", + "attribute of boxes to use for box labels, if any. The boolean argument\n", + "`port_labels` controls the labeling of ports by numerical values and the\n", + "argument `junction_labels` specifies the data attribute of junctions to use\n", + "for junction labels. Note that the macro `@relation` creates wiring diagrams\n", + "with `name` attribute for boxes and `variable` attribute for junctions." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\", :label => \"R\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\", :label => \"S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box3\", :label => \"T\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer1\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer2\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer3\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"w\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction2\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"x\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"y\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction4\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"z\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "R\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "w\n", + "\n", + "\n", + "\n", + "n1--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "x\n", + "\n", + "\n", + "\n", + "n1--n8\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "S\n", + "\n", + "\n", + "\n", + "n2--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "y\n", + "\n", + "\n", + "\n", + "n2--n9\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "T\n", + "\n", + "\n", + "\n", + "n3--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "z\n", + "\n", + "\n", + "\n", + "n3--n10\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4--n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5--n9\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n6--n10\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(diagram, box_labels=:name,\n", + " port_labels=false, junction_labels=:variable)" + ], + "metadata": {}, + "execution_count": 21 + }, + { + "cell_type": "markdown", + "source": [ + "By default, all junctions are shown. The keyword argument `implicit_junctions`\n", + "omits any junctions which have exactly two incident ports." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\", :label => \"R\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\", :label => \"S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box3\", :label => \"T\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer1\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer2\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer3\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "R\n", + "\n", + "\n", + "\n", + "\n", + "n1--n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n1--n7\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "S\n", + "\n", + "\n", + "\n", + "\n", + "n2--n5\n", + "\n", + "\n", + "\n", + "\n", + "n2--n7\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "T\n", + "\n", + "\n", + "\n", + "\n", + "n3--n6\n", + "\n", + "\n", + "\n", + "\n", + "n3--n7\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 22 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(diagram, box_labels=:name,\n", + " port_labels=false, implicit_junctions=true)" + ], + "metadata": {}, + "execution_count": 22 + }, + { + "cell_type": "markdown", + "source": [ + "## Custom styles" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The visual appearance of wiring diagrams can be customized by setting Graphviz\n", + "[attributes](https://www.graphviz.org/doc/info/attrs.html) at the graph, node,\n", + "edge, and cell levels. Graph, node, and edge attributes are described in the\n", + "Graphviz documentation. Cell attributes are passed to the primary cell of the\n", + "[HTML-like label](https://www.graphviz.org/doc/info/shapes.html#html) used for\n", + "the boxes." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0.333\", :height => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"s\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :headlabel => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"n\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :headlabel => \"B\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"s\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"n\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :headlabel => \"C\", :id => \"e3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\", :labelangle => \"25\", :labeldistance => \"2\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:s->n1:n\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n1:s->n2:n\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2:s->n0out1:n\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ], + "cell_type": "code", + "source": [ + "A, B, C = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C)\n", + "f, g = Hom(:f, A, B), Hom(:g, B, C)\n", + "\n", + "to_graphviz(compose(f,g),\n", + " labels = true, label_attr=:headlabel,\n", + " node_attrs = Dict(\n", + " :fontname => \"Courier\",\n", + " ),\n", + " edge_attrs = Dict(\n", + " :fontname => \"Courier\",\n", + " :labelangle => \"25\",\n", + " :labeldistance => \"2\",\n", + " ),\n", + " cell_attrs = Dict(\n", + " :bgcolor => \"lavender\",\n", + " )\n", + ")" + ], + "metadata": {}, + "execution_count": 23 + }, + { + "cell_type": "markdown", + "source": [ + "## Output formats" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The function `to_graphviz` returns an object of a type `Graphviz.Graph`,\n", + "representing a Graphviz graph as an abstract syntax tree. When displayed\n", + "interactively, this object is automatically run through Graphviz and rendered\n", + "as an SVG image. Sometimes it is convenient to perform this process manually,\n", + "to change the output format or further customize the generated dot file." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "To generate a dot file, use the builtin pretty-printer. This feature does not\n", + "require Graphviz to be installed." + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "digraph G {\n", + " graph [fontname=\"Serif\",rankdir=\"TB\"];\n", + " node [fontname=\"Serif\",shape=\"none\",width=\"0\",height=\"0\",margin=\"0\"];\n", + " edge [arrowsize=\"0.5\",fontname=\"Serif\"];\n", + " {\n", + " graph [rank=\"source\",rankdir=\"LR\"];\n", + " node [style=\"invis\",shape=\"none\",label=\"\",width=\"0.333\",height=\"0\"];\n", + " edge [style=\"invis\"];\n", + " n0in1 [id=\"in1\"];\n", + " }\n", + " {\n", + " graph [rank=\"sink\",rankdir=\"LR\"];\n", + " node [style=\"invis\",shape=\"none\",label=\"\",width=\"0.333\",height=\"0\"];\n", + " edge [style=\"invis\"];\n", + " n0out1 [id=\"out1\"];\n", + " }\n", + " n1 [color=\"black\",comment=\"f\",fillcolor=\"white\",id=\"n1\",label=<\n", + "\n", + "\n", + "\n", + "
f
>,style=\"solid\"];\n", + " n2 [color=\"black\",comment=\"g\",fillcolor=\"white\",id=\"n2\",label=<\n", + "\n", + "\n", + "\n", + "
g
>,style=\"solid\"];\n", + " n0in1:s -> n1:in1:n [comment=\"A\",id=\"e1\"];\n", + " n1:out1:s -> n2:in1:n [comment=\"B\",id=\"e2\"];\n", + " n2:out1:s -> n0out1:n [comment=\"C\",id=\"e3\"];\n", + "}\n" + ] + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Graphics: Graphviz\n", + "\n", + "graph = to_graphviz(compose(f,g))\n", + "Graphviz.pprint(graph)" + ], + "metadata": {}, + "execution_count": 24 + }, + { + "cell_type": "markdown", + "source": [ + "Catlab provides a simple wrapper around the Graphviz command-line programs.\n", + "For example, here is the JSON output for the graph." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 9 entries:\n :name => \"G\"\n :directed => true\n :strict => false\n :bb => \"0,0,24,160\"\n :fontname => \"Serif\"\n :rankdir => \"TB\"\n :_subgraph_cnt => 2\n :objects => Object[{…\n :edges => Object[{…" + }, + "metadata": {}, + "execution_count": 25 + } + ], + "cell_type": "code", + "source": [ + "import JSON3\n", + "\n", + "JSON3.read(Graphviz.run_graphviz(graph, format=\"json0\"))" + ], + "metadata": {}, + "execution_count": 25 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphics/graphviz_wiring_diagrams/index.html b/v0.16.12/generated/graphics/graphviz_wiring_diagrams/index.html new file mode 100644 index 000000000..a52a94a26 --- /dev/null +++ b/v0.16.12/generated/graphics/graphviz_wiring_diagrams/index.html @@ -0,0 +1,1542 @@ + +Drawing wiring diagrams in Graphviz · Catlab.jl

Drawing wiring diagrams in Graphviz

Catlab can draw wiring diagrams using Graphviz. Directed wiring diagrams are drawn using the dot program and undirected wiring diagrams using neato and fdp. This feature requires that Graphviz be installed, but does not require any additional Julia packages.

using Catlab.WiringDiagrams, Catlab.Graphics

Directed wiring diagrams

Symmetric monoidal category

using Catlab.Theories
+
+A, B = Ob(FreeSymmetricMonoidalCategory, :A, :B)
+f = Hom(:f, A, B)
+g = Hom(:g, B, A)
+h = Hom(:h, otimes(A,B), otimes(A,B));

To start, here are a few very simple examples.

to_graphviz(f)
to_graphviz(compose(f,g))
to_graphviz(otimes(f,g))

In the next example, notice how Graphviz automatically "untwists" the double braiding to minimize edge crossings.

to_graphviz(compose(braid(A,A), otimes(f,f), braid(B,B)))

Here is a larger composite morphism.

composite = compose(otimes(g,f), h, otimes(f,g))
+to_graphviz(composite)

By default, the wiring diagram is laid out from top to bottom. Other layout orientations can be requested, such as left-to-right or bottom-to-top:

to_graphviz(composite, orientation=LeftToRight)
to_graphviz(composite, orientation=BottomToTop)

When working with very large diagrams (larger than the ones shown here), it is sometimes convenient to omit the ports of the outer box and any wires attached to them.

to_graphviz(composite, outer_ports=false)

Biproduct category

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

By default, copies and merges are drawn the way they are represented internally, as multiple wires.

f1 = compose(mcopy(A), otimes(f,f))
+to_graphviz(f1)
f2 = compose(mcopy(A), otimes(f,f), mmerge(B))
+to_graphviz(f2)

To draw nodes for copies and merges, we need to add junctions to the wiring diagram.

to_graphviz(add_junctions!(to_wiring_diagram(f1)))
to_graphviz(add_junctions!(to_wiring_diagram(f2)))

Traced monoidal category

A, B, X, Y = Ob(FreeTracedMonoidalCategory, :A, :B, :X, :Y)
+f = Hom(:f, otimes(X,A), otimes(X,B))
+
+to_graphviz(trace(X, A, B, f))
to_graphviz(trace(X, A, B, f), orientation=LeftToRight)
g, h = Hom(:g, A, A), Hom(:h, B, B)
+
+trace_naturality = trace(X, A, B, compose(otimes(id(X),g), f, otimes(id(X),h)))
+to_graphviz(trace_naturality, orientation=LeftToRight)

Undirected wiring diagrams

The composite of two binary relations:

using Catlab.Programs: @relation
+
+diagram = @relation (x,z) where (x,y,z) begin
+    R(x,y)
+    S(y,z)
+end
+to_graphviz(diagram, box_labels=:name)

A "wheel"-shaped composition of relations:

diagram = @relation (x,y,z) where (w,x,y,z) begin
+    R(x,w)
+    S(y,w)
+    T(z,w)
+end
+to_graphviz(diagram, box_labels=:name)

As these examples show, the box_labels keyword argument specifies the data attribute of boxes to use for box labels, if any. The boolean argument port_labels controls the labeling of ports by numerical values and the argument junction_labels specifies the data attribute of junctions to use for junction labels. Note that the macro @relation creates wiring diagrams with name attribute for boxes and variable attribute for junctions.

to_graphviz(diagram, box_labels=:name,
+            port_labels=false, junction_labels=:variable)

By default, all junctions are shown. The keyword argument implicit_junctions omits any junctions which have exactly two incident ports.

to_graphviz(diagram, box_labels=:name,
+            port_labels=false, implicit_junctions=true)

Custom styles

The visual appearance of wiring diagrams can be customized by setting Graphviz attributes at the graph, node, edge, and cell levels. Graph, node, and edge attributes are described in the Graphviz documentation. Cell attributes are passed to the primary cell of the HTML-like label used for the boxes.

A, B, C = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C)
+f, g = Hom(:f, A, B), Hom(:g, B, C)
+
+to_graphviz(compose(f,g),
+  labels = true, label_attr=:headlabel,
+  node_attrs = Dict(
+    :fontname => "Courier",
+  ),
+  edge_attrs = Dict(
+    :fontname => "Courier",
+    :labelangle => "25",
+    :labeldistance => "2",
+  ),
+  cell_attrs = Dict(
+    :bgcolor => "lavender",
+  )
+)

Output formats

The function to_graphviz returns an object of a type Graphviz.Graph, representing a Graphviz graph as an abstract syntax tree. When displayed interactively, this object is automatically run through Graphviz and rendered as an SVG image. Sometimes it is convenient to perform this process manually, to change the output format or further customize the generated dot file.

To generate a dot file, use the builtin pretty-printer. This feature does not require Graphviz to be installed.

using Catlab.Graphics: Graphviz
+
+graph = to_graphviz(compose(f,g))
+Graphviz.pprint(graph)
digraph G {
+  graph [fontname="Serif",rankdir="TB"];
+  node [fontname="Serif",shape="none",width="0",height="0",margin="0"];
+  edge [arrowsize="0.5",fontname="Serif"];
+  {
+    graph [rank="source",rankdir="LR"];
+    node [style="invis",shape="none",label="",width="0.333",height="0"];
+    edge [style="invis"];
+    n0in1 [id="in1"];
+  }
+  {
+    graph [rank="sink",rankdir="LR"];
+    node [style="invis",shape="none",label="",width="0.333",height="0"];
+    edge [style="invis"];
+    n0out1 [id="out1"];
+  }
+  n1 [color="black",comment="f",fillcolor="white",id="n1",label=<<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0">
+<TR><TD><TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD HEIGHT="0" WIDTH="24" PORT="in1"></TD></TR></TABLE></TD></TR>
+<TR><TD BORDER="1" CELLPADDING="4">f</TD></TR>
+<TR><TD><TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD HEIGHT="0" WIDTH="24" PORT="out1"></TD></TR></TABLE></TD></TR>
+</TABLE>>,style="solid"];
+  n2 [color="black",comment="g",fillcolor="white",id="n2",label=<<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0">
+<TR><TD><TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD HEIGHT="0" WIDTH="24" PORT="in1"></TD></TR></TABLE></TD></TR>
+<TR><TD BORDER="1" CELLPADDING="4">g</TD></TR>
+<TR><TD><TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD HEIGHT="0" WIDTH="24" PORT="out1"></TD></TR></TABLE></TD></TR>
+</TABLE>>,style="solid"];
+  n0in1:s -> n1:in1:n [comment="A",id="e1"];
+  n1:out1:s -> n2:in1:n [comment="B",id="e2"];
+  n2:out1:s -> n0out1:n [comment="C",id="e3"];
+}

Catlab provides a simple wrapper around the Graphviz command-line programs. For example, here is the JSON output for the graph.

import JSON3
+
+JSON3.read(Graphviz.run_graphviz(graph, format="json0"))
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 9 entries:
+  :name          => "G"
+  :directed      => true
+  :strict        => false
+  :bb            => "0,0,24,160"
+  :fontname      => "Serif"
+  :rankdir       => "TB"
+  :_subgraph_cnt => 2
+  :objects       => Object[{…
+  :edges         => Object[{…
diff --git a/v0.16.12/generated/graphics/layouts_vs_drawings.ipynb b/v0.16.12/generated/graphics/layouts_vs_drawings.ipynb new file mode 100644 index 000000000..b4628b3e5 --- /dev/null +++ b/v0.16.12/generated/graphics/layouts_vs_drawings.ipynb @@ -0,0 +1,2456 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Layouts versus drawings of wiring diagrams\n", + "\n", + "\n", + "In Catlab, layout and drawing (rendering) of wiring diagrams are mostly\n", + "decoupled. This notebook shows how to lay out diagrams using Graphviz's\n", + "rank-based layout or Catlab's series-parallel layout and then render them\n", + "using Compose.jl or TikZ." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The morphism we will visualize is:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "f⊗(f⋅g)⊗(f⋅g⋅h): X⊗X⊗X → X⊗X⊗X", + "text/latex": "$f \\otimes \\left(f \\cdot g\\right) \\otimes \\left(f \\cdot g \\cdot h\\right) : X \\otimes X \\otimes X \\to X \\otimes X \\otimes X$" + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Theories\n", + "\n", + "X = Ob(FreeSymmetricMonoidalCategory, :X)\n", + "f, g, h = (Hom(sym, X, X) for sym in (:f, :g, :h))\n", + "\n", + "expr = otimes(f, compose(f,g), compose(f,g,h))" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "Let's convert this expression into a wiring diagram. This yields a purely\n", + "combinatorial object, as evidenced by its underlying graph." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagramGraphACSet{Int64} {V:8, E:9, ID:0}\n┌───┬─────┐\n│\u001b[1m V │\u001b[1m box │\n├───┼─────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 2 │\n│\u001b[1m 3 │ 3 │\n│\u001b[1m 4 │ 4 │\n│\u001b[1m 5 │ 5 │\n│\u001b[1m 6 │ 6 │\n│\u001b[1m 7 │ -2 │\n│\u001b[1m 8 │ -1 │\n└───┴─────┘\n┌───┬─────┬─────┬──────┐\n│\u001b[1m E │\u001b[1m src │\u001b[1m tgt │\u001b[1m wire │\n├───┼─────┼─────┼──────┤\n│\u001b[1m 1 │ 2 │ 3 │ 1 │\n│\u001b[1m 2 │ 5 │ 6 │ 2 │\n│\u001b[1m 3 │ 4 │ 5 │ 3 │\n│\u001b[1m 4 │ 7 │ 1 │ 1 │\n│\u001b[1m 5 │ 7 │ 2 │ 2 │\n│\u001b[1m 6 │ 7 │ 4 │ 3 │\n│\u001b[1m 7 │ 1 │ 8 │ 1 │\n│\u001b[1m 8 │ 3 │ 8 │ 2 │\n│\u001b[1m 9 │ 6 │ 8 │ 3 │\n└───┴─────┴─────┴──────┘\n", + "text/html": [ + "
\n", + "Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagramGraphACSet{Int64} {V:8, E:9, ID:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Vbox
11
22
33
44
55
66
7-2
8-1
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Esrctgtwire
1231
2562
3453
4711
5722
6743
7181
8382
9683
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.WiringDiagrams, Catlab.Graphics\n", + "\n", + "diagram = to_wiring_diagram(expr)\n", + "WiringDiagrams.graph(diagram)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "## Graphviz layout" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Calling `to_graphviz` both lays out and draws the diagram, entirely within\n", + "Graphviz." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Node(\"n0in3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Node(\"n0out3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n5\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n6\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in3\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"X\", :id => \"e9\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in3:e->n4:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n0out2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n5:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n5:e->n6:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n6:e->n0out3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(diagram, orientation=LeftToRight)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "To get just the layout from Graphviz, we call `graphviz_layout` instead. We\n", + "can then render this layout using Compose.jl. Note that the Graphviz layout\n", + "has units in points." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-101.0, -55.0, 202.0, 110.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((64.00008cx, 42.5cy), (82.25004cx, 42.5cy), (82.25004cx, 42.5cy), (100.5cx, 42.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((8.00008cx, -0.5cy), (54.25004cx, -0.5cy), (54.25004cx, 0.5cy), (100.5cx, 0.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((61.99992cx, -42.5cy), (81.24996cx, -42.5cy), (81.24996cx, -41.5cy), (100.5cx, -41.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((8.00008cx, 42.5cy), (26.000000000000004cx, 42.5cy), (26.0cx, 42.5cy), (43.99992cx, 42.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-48.00008cx, 42.5cy), (-30.000079999999997cx, 42.5cy), (-30.00008cx, 42.5cy), (-12.00008cx, 42.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-48.00008cx, -0.5cy), (-30.000079999999997cx, -0.5cy), (-30.00008cx, -0.5cy), (-12.00008cx, -0.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-100.5cx, 42.5cy), (-82.24996cx, 42.5cy), (-82.24996cx, 42.5cy), (-63.99992cx, 42.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-100.5cx, 0.5cy), (-82.24996cx, 0.5cy), (-82.24996cx, -0.5cy), (-63.99992cx, -0.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-100.5cx, -41.5cy), (-27.24996cx, -41.5cy), (-27.24996cx, -42.5cy), (46.00008cx, -42.5cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((43.99992cx, 30.00008cy), (20.00016cx, 24.99984cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"h\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-12.00008cx, 30.00008cy), (20.00016cx, 24.99984cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-63.99992cx, 30.00008cy), (15.99984cx, 24.99984cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-12.00008cx, -12.99992cy), (20.00016cx, 24.99984cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-63.99992cx, -12.99992cy), (15.99984cx, 24.99984cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((46.00008cx, -54.99992cy), (15.99984cx, 24.99984cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 71.2611111111111mm, 38.80555555555555mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "import Compose\n", + "\n", + "layout = graphviz_layout(diagram, orientation=LeftToRight)\n", + "layout_to_composejl(layout, base_unit=Compose.pt)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "The same layout can be rendered in TikZ:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"202\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"110\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"16\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"25\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"54\", \"42.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"16\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"25\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-56\", \"0.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"20\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"25\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0.5\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Node(\"n4\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"16\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"25\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-56\", \"-42.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n5\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"20\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"25\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"-42.5\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Node(\"n6\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"20\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"25\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"54\", \"-42.5\"), \"\\$h\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,41.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,-0.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,-42.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n4.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n4.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n5.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n5.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n6.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,41.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,-0.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n6.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,-42.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"1pt\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "import TikzPictures\n", + "\n", + "layout_to_tikz(layout, base_unit=\"1pt\")" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "## Series-parallel layout" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Catlab has its own layout system based on series-parallel decomposition. In\n", + "this case, the layout exactly recovers the structure of the morphism\n", + "expression created at the beginning." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "ComposePicture(Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), Compose.UnitBox{Float64, Float64, Float64, Float64}(-7.0, -5.0, 14.0, 10.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((5.0cx, 3.0cy), (6.0cx, 3.0cy), (6.0cx, 3.000035389161488cy), (7.0cx, 3.000035389161488cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 0.0cy), (5.0cx, 0.0cy), (5.0cx, 4.0007782582127306e-16cy), (7.0cx, 4.0007782582127306e-16cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -3.0cy), (4.0cx, -3.0cy), (4.0cx, -3.000035389161489cy), (7.0cx, -3.000035389161489cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, 3.0cy), (-2.0cx, 3.0cy), (-2.0cx, 3.0cy), (-1.0cx, 3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, 3.0cy), (2.0cx, 3.0cy), (2.0cx, 3.0cy), (3.0cx, 3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 0.0cy), (0.0cx, 0.0cy), (0.0cx, 0.0cy), (1.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, 3.000035389161488cy), (-6.0cx, 3.000035389161488cy), (-6.0cx, 3.0cy), (-5.0cx, 3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, 4.0007782582127306e-16cy), (-5.0cx, 4.0007782582127306e-16cy), (-5.0cx, 0.0cy), (-3.0cx, 0.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}}(Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}[Compose.CurvePrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-7.0cx, -3.000035389161489cy), (-4.0cx, -3.000035389161489cy), (-4.0cx, -3.0cy), (-1.0cx, -3.0cy))], Symbol(\"\"))]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 0, false, false, false, false, nothing, nothing, 0.0, :wire)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :wires), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((3.0cx, 2.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"h\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, 2.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-5.0cx, 2.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((1.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"g\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-3.0cx, -1.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}}((-1.0cx, -4.0cy), (2.0cx, 2.0cy)), Compose.UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0, 0.0mm, 0.0mm, 0.0mm, 0.0mm), nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}}(Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}[Compose.TextPrimitive{Tuple{Measures.Length{:cx, Float64}, Measures.Length{:cy, Float64}}, Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}, Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}}((0.5cx, 0.5cy), \"f\", Compose.HCenter(), Compose.VCenter(), Compose.Rotation{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}(0.0, (0.5w, 0.5h)), (0.0mm, 0.0mm))], Symbol(\"\"))]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, false)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, false)], Symbol(\"\")), Compose.Form{Compose.LinePrimitive}(Compose.LinePrimitive[Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 0.0h), (1.0w + -1.0mm, 0.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(0.0w, 1.0mm), (0.0w, 1.0h + -1.0mm)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0mm, 1.0h), (1.0w + -1.0mm, 1.0h)]), Compose.LinePrimitive{Tuple{Measures.Measure, Measures.Measure}}(Tuple{Measures.Measure, Measures.Measure}[(1.0w, 1.0mm), (1.0w, 1.0h + -1.0mm)])], Symbol(\"\"))]), List([]), 2, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\")), Compose.Context(Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}((0.0w, 0.0h), (1.0w, 1.0h)), nothing, nothing, nothing, nothing, List([]), List([Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0h + -1.0mm), 1.0mm, 0.0, 1.5707963267948966, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}}, Measures.AbsoluteLength}((1.0mm, 1.0h + -1.0mm), 1.0mm, 1.5707963267948966, 3.141592653589793, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0w + -1.0mm, 1.0mm), 1.0mm, 4.71238898038469, 0.0, true)], Symbol(\"\")), Compose.Form{Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}}(Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}[Compose.ArcPrimitive{Tuple{Measures.AbsoluteLength, Measures.AbsoluteLength}, Measures.AbsoluteLength}((1.0mm, 1.0mm), 1.0mm, 3.141592653589793, 4.71238898038469, true)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}}(Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}[Compose.RectanglePrimitive{Tuple{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.Length{:w, Float64}, Measures.Add{Measures.Add{Measures.Length{:h, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}}((0.0w, 0.7354497354497354mm), 1.0w, 1.0h + -2.0mm + 0.5291005291005292mm)], Symbol(\"\")), Compose.Form{Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}}(Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}[Compose.RectanglePrimitive{Tuple{Measures.AbsoluteLength, Measures.Length{:h, Float64}}, Measures.Add{Measures.Add{Measures.Length{:w, Float64}, Measures.AbsoluteLength}, Measures.AbsoluteLength}, Measures.Length{:h, Float64}}((0.7354497354497354mm, 0.0h), 1.0w + -2.0mm + 0.5291005291005292mm, 1.0h)], Symbol(\"\"))]), List([Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([Compose.Property{Compose.FillPrimitive}(Compose.FillPrimitive[Compose.FillPrimitive(RGBA{Float64}(0.0,0.0,0.0,0.0))]), Compose.Property{Compose.StrokePrimitive}(Compose.StrokePrimitive[Compose.StrokePrimitive(RGBA{Float64}(0.0,0.0,0.0,1.0))])]), 1, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, Symbol(\"\"))]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :box)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :boxes)]), List([]), List([]), 0, false, false, false, false, nothing, nothing, 0.0, :diagram), 56.0mm, 40.0mm)", + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + "\n" + ], + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " h\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " g\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " f\n", + " \n", + " \n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "layout = layout_diagram(FreeSymmetricMonoidalCategory, diagram,\n", + " orientation=LeftToRight)\n", + "layout_to_composejl(layout)" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"14\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"10\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"3\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Node(\"n4\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-4\", \"-3\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n5\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"-3\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Node(\"n6\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"4\", \"-3\"), \"\\$h\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n4.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n5.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n6.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n4.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n5.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n6.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "layout_to_tikz(layout)" + ], + "metadata": {}, + "execution_count": 7 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphics/layouts_vs_drawings/4c97b37e.svg b/v0.16.12/generated/graphics/layouts_vs_drawings/4c97b37e.svg new file mode 100644 index 000000000..6df47f668 --- /dev/null +++ b/v0.16.12/generated/graphics/layouts_vs_drawings/4c97b37e.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + diff --git a/v0.16.12/generated/graphics/layouts_vs_drawings/5f51bd71.svg b/v0.16.12/generated/graphics/layouts_vs_drawings/5f51bd71.svg new file mode 100644 index 000000000..df5dafb66 --- /dev/null +++ b/v0.16.12/generated/graphics/layouts_vs_drawings/5f51bd71.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/layouts_vs_drawings/8a9c16c0.svg b/v0.16.12/generated/graphics/layouts_vs_drawings/8a9c16c0.svg new file mode 100644 index 000000000..3852e051a --- /dev/null +++ b/v0.16.12/generated/graphics/layouts_vs_drawings/8a9c16c0.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + + + + diff --git a/v0.16.12/generated/graphics/layouts_vs_drawings/94d70f33.svg b/v0.16.12/generated/graphics/layouts_vs_drawings/94d70f33.svg new file mode 100644 index 000000000..9ab85faa1 --- /dev/null +++ b/v0.16.12/generated/graphics/layouts_vs_drawings/94d70f33.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/layouts_vs_drawings/index.html b/v0.16.12/generated/graphics/layouts_vs_drawings/index.html new file mode 100644 index 000000000..4b97ea560 --- /dev/null +++ b/v0.16.12/generated/graphics/layouts_vs_drawings/index.html @@ -0,0 +1,256 @@ + +Layouts versus drawings of wiring diagrams · Catlab.jl

Layouts versus drawings of wiring diagrams

In Catlab, layout and drawing (rendering) of wiring diagrams are mostly decoupled. This notebook shows how to lay out diagrams using Graphviz's rank-based layout or Catlab's series-parallel layout and then render them using Compose.jl or TikZ.

The morphism we will visualize is:

using Catlab.Theories
+
+X = Ob(FreeSymmetricMonoidalCategory, :X)
+f, g, h = (Hom(sym, X, X) for sym in (:f, :g, :h))
+
+expr = otimes(f, compose(f,g), compose(f,g,h))

\[f \otimes \left(f \cdot g\right) \otimes \left(f \cdot g \cdot h\right) : X \otimes X \otimes X \to X \otimes X \otimes X\]

Let's convert this expression into a wiring diagram. This yields a purely combinatorial object, as evidenced by its underlying graph.

using Catlab.WiringDiagrams, Catlab.Graphics
+
+diagram = to_wiring_diagram(expr)
+WiringDiagrams.graph(diagram)
+Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagramGraphACSet{Int64} {V:8, E:9, ID:0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Vbox
11
22
33
44
55
66
7-2
8-1
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Esrctgtwire
1231
2562
3453
4711
5722
6743
7181
8382
9683
+
+

Graphviz layout

Calling to_graphviz both lays out and draws the diagram, entirely within Graphviz.

to_graphviz(diagram, orientation=LeftToRight)

To get just the layout from Graphviz, we call graphviz_layout instead. We can then render this layout using Compose.jl. Note that the Graphviz layout has units in points.

import Compose
+
+layout = graphviz_layout(diagram, orientation=LeftToRight)
+layout_to_composejl(layout, base_unit=Compose.pt)
Example block output

The same layout can be rendered in TikZ:

import TikzPictures
+
+layout_to_tikz(layout, base_unit="1pt")
Example block output

Series-parallel layout

Catlab has its own layout system based on series-parallel decomposition. In this case, the layout exactly recovers the structure of the morphism expression created at the beginning.

layout = layout_diagram(FreeSymmetricMonoidalCategory, diagram,
+                        orientation=LeftToRight)
+layout_to_composejl(layout)
Example block output
layout_to_tikz(layout)
Example block output
diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams.ipynb b/v0.16.12/generated/graphics/tikz_wiring_diagrams.ipynb new file mode 100644 index 000000000..8a1bd0997 --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams.ipynb @@ -0,0 +1,1940 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Drawing wiring diagrams in TikZ\n", + "\n", + "\n", + "Catlab can draw morphism expressions as TikZ pictures. To use this feature,\n", + "LaTeX must be installed and the Julia package\n", + "[TikzPictures.jl](https://github.com/sisl/TikzPictures.jl) must be loaded.\n", + "\n", + "For best results, it is recommended to load the packages\n", + "[Convex.j](https://github.com/JuliaOpt/Convex.jl) and\n", + "[SCS.jl](https://github.com/JuliaOpt/SCS.jl). When available they are used to\n", + "optimize the layout of the outer ports." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.WiringDiagrams, Catlab.Graphics\n", + "\n", + "import Convex, SCS\n", + "import TikzPictures" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Examples" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "### Symmetric monoidal category" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.Theories\n", + "\n", + "A, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)\n", + "f, g = Hom(:f, A, B), Hom(:g, B, A);" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "To start, here are a few very simple examples." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"6\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$B\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f, labels=true)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"10\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$B\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f⋅g, labels=true)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"7\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"6\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-1.5\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"1.5\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.north)+(-1.5,0)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.north\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.north)+(1.5,0)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.north\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$B\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.south\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(-1.5,0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$B\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.south\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(1.5,0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$A\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f⊗g, labels=true, orientation=TopToBottom)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Here is a more complex example, involving generators with compound domains and\n", + "codomains." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"22\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"13\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-8\", \"4.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-8\", \"1.5\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-8\", \"-1.5\"), \"\\$h\\$\"), Catlab.Graphics.TikZ.Node(\"n4\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-8\", \"-4.5\"), \"\\$k\\$\"), Catlab.Graphics.TikZ.Node(\"n5\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"2\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-4\", \"3\"), \"\\$m\\$\"), Catlab.Graphics.TikZ.Node(\"n6\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"2\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-4\", \"-3\"), \"\\$n\\$\"), Catlab.Graphics.TikZ.Node(\"n7\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"2\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"11\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\\$l\\$\"), Catlab.Graphics.TikZ.Node(\"n8\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"2\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"4\", \"3\"), \"\\$n\\$\"), Catlab.Graphics.TikZ.Node(\"n9\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"2\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"4\", \"-3\"), \"\\$m\\$\") … Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n6.east)+(0,1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n7.west)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n5.east)+(0,-1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n7.west)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n4.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n6.west)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n5.west)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n6.west)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(n5.west)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n10.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,4.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n11.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n12.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n13.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-4.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "h, k = Hom(:h, C, D), Hom(:k, D, C)\n", + "m, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)\n", + "q = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)\n", + "\n", + "to_tikz((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Identities and braidings appear as wires." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(id(A), labels=true)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"4\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"135\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-135\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$B\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.25 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(braid(A,B), labels=true, labels_pos=0.25)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"10\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"1.5\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"-1.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-135\")]), Catlab.Graphics.TikZ.Coordinate(\"-3\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"45\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"135\")]), Catlab.Graphics.TikZ.Coordinate(\"-3\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-45\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-135\")]), Catlab.Graphics.TikZ.Coordinate(\"3\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"135\")]), Catlab.Graphics.TikZ.Coordinate(\"3\", \"0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "The isomorphism $A \\otimes B \\otimes C \\to C \\otimes B \\otimes A$ induced by\n", + "the permutation $(3\\ 2\\ 1)$ is a composite of braidings and identities." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"8\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"10\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-135\")]), Catlab.Graphics.TikZ.Coordinate(\"-2\", \"1.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"135\")]), Catlab.Graphics.TikZ.Coordinate(\"2\", \"1.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$B\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"-2\", \"-3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-135\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"-1.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"45\"), Catlab.Graphics.TikZ.Property(\"in\", \"-135\")]), Catlab.Graphics.TikZ.Coordinate(\"2\", \"1.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$C\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"135\")]), Catlab.Graphics.TikZ.Coordinate(\"-2\", \"1.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-45\"), Catlab.Graphics.TikZ.Property(\"in\", \"135\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"-1.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-45\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"2\", \"-3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.1pt with {#1}\")])]), Catlab.Graphics.TikZ.Property(\"->/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position -0.1pt with {\\\\arrow{Stealth}}\")])]), Catlab.Graphics.TikZ.Property(\"<-/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position -0.1pt with {\\\\arrow{Stealth[reversed]}}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\", \"arrows.meta\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))\n", + "\n", + "to_tikz(σ, arrowtip=\"Stealth\", arrowtip_pos=\"-0.1pt\",\n", + " labels=true, labels_pos=\"0.1pt\")" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "By default, anchor points are added along identity and braiding wires to\n", + "reproduce the expression structure in the layout. The anchors can be disabled\n", + "to get a more \"unbiased\" layout." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"8\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"10\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$B\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$C\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.1pt with {#1}\")])]), Catlab.Graphics.TikZ.Property(\"->/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position -0.1pt with {\\\\arrow{Stealth}}\")])]), Catlab.Graphics.TikZ.Property(\"<-/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position -0.1pt with {\\\\arrow{Stealth[reversed]}}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\", \"arrows.meta\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(σ, anchor_wires=false, arrowtip=\"Stealth\", arrowtip_pos=\"-0.1pt\",\n", + " labels=true, labels_pos=\"0.1pt\")" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "### Biproduct category" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"4.5\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)\n", + "f = Hom(:f, A, B)\n", + "\n", + "to_tikz(mcopy(A), labels=true)" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"4.5\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(delete(A), labels=true)" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"11\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-3.25\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"1.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"-1.5\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n4\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"3.25\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n4.-150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n4.150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-30\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"30\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n4.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$B\\$};}\")])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(mcopy(A)⋅(f⊗f)⋅mmerge(B), labels=true)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"13\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"6.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-3\", \"1\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"3\", \"1\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.north)+(-3,0.0)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.90\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.north)+(3,0.0)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.90\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$B\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-60\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-60\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(4.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-120\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-120\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(-4.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-120\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-120\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(-1.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-60\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-60\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(1.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(mcopy(A⊗B), orientation=TopToBottom, labels=true)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"19\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"6.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-6\", \"1\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"1\"), \"\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"6\", \"1\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.north)+(-6,0.0)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.90\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$A\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.north\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.90\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$B\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.north)+(6,0.0)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.90\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=east] {\\$C\\$};}\")]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.-120\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-120\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(-1.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-120\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-120\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(-7.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-60\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-60\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(4.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-60\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-60\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(1.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.-60\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-60\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(7.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-120\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-120\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.south)+(-4.5,-0.0)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(mcopy(A⊗B⊗C), orientation=TopToBottom, labels=true)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "### Compact closed category" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The unit and co-unit of a compact closed category appear as caps and cups." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"4\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"invisible\", nothing)], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.center\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"90\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.center\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"invisible/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\"), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])]), Catlab.Graphics.TikZ.Property(\"->/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {\\\\arrow{Stealth}}\")])]), Catlab.Graphics.TikZ.Property(\"<-/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {\\\\arrow{Stealth[reversed]}}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\", \"arrows.meta\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "A, B = Ob(FreeCompactClosedCategory, :A, :B)\n", + "\n", + "to_tikz(dunit(A), arrowtip=\"Stealth\", labels=true)" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"4\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"invisible\", nothing)], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.center\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.center\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", \"{\\\\node[anchor=south] {\\$A\\$};}\"), Catlab.Graphics.TikZ.Property(\"->\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"invisible/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\"), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {#1}\")])]), Catlab.Graphics.TikZ.Property(\"->/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {\\\\arrow{Stealth}}\")])]), Catlab.Graphics.TikZ.Property(\"<-/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"postaction\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"decorate\", nothing)]), Catlab.Graphics.TikZ.Property(\"decoration\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"markings\", nothing), Catlab.Graphics.TikZ.Property(\"mark\", \"at position 0.5 with {\\\\arrow{Stealth[reversed]}}\")])])]), [\"calc\", \"shapes.geometric\", \"decorations.markings\", \"arrows.meta\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(dcounit(A), arrowtip=\"Stealth\", labels=true)" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "cell_type": "markdown", + "source": [ + "In a self-dual compact closed category, such as a bicategory of relations,\n", + "every morphism $f: A \\to B$ has a transpose $f^\\dagger: B \\to A$ given by\n", + "bending wires:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"10\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"invisible\", nothing)], Catlab.Graphics.TikZ.Coordinate(\"-3\", \"1.5\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"invisible\", nothing)], Catlab.Graphics.TikZ.Coordinate(\"3\", \"-1.5\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(0,-3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"-3\", \"-3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"-3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.center\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.center\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.center\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.center\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"90\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"3\", \"3\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0,3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"rectangle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"invisible/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\"), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "A, B = Ob(FreeBicategoryRelations, :A, :B)\n", + "f = Hom(:f, A, B)\n", + "\n", + "to_tikz((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))" + ], + "metadata": {}, + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "### Abelian bicategory of relations" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "In an abelian bicategory of relations, such as the category of linear\n", + "relations, the duplication morphisms $\\Delta_X: X \\to X \\oplus X$ and addition\n", + "morphisms $\\blacktriangledown_X: X \\oplus X \\to X$ belong to a bimonoid. Among\n", + "other things, this means that the following two morphisms are equal." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"variant junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-1.25\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"1.25\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,-1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"variant junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ], + "cell_type": "code", + "source": [ + "X = Ob(FreeAbelianBicategoryRelations, :X)\n", + "\n", + "to_tikz(plus(X) ⋅ mcopy(X))" + ], + "metadata": {}, + "execution_count": 20 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"9\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"13\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2.25\", \"3\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2.25\", \"-3\"), \"\"), Catlab.Graphics.TikZ.Node(\"n3\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"variant junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2.25\", \"3\"), \"\"), Catlab.Graphics.TikZ.Node(\"n4\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"variant junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2.25\", \"-3\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,-3)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"-4.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n4.-150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.Coordinate(\"0\", \"4.5\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-30\"), Catlab.Graphics.TikZ.Property(\"in\", \"150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n4.150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"30\"), Catlab.Graphics.TikZ.Property(\"in\", \"-150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n3.-150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n3.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n4.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,-3)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"variant junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ], + "cell_type": "code", + "source": [ + "to_tikz((mcopy(X)⊕mcopy(X)) ⋅ (id(X)⊕swap(X,X)⊕id(X)) ⋅ (plus(X)⊕plus(X)))" + ], + "metadata": {}, + "execution_count": 21 + }, + { + "cell_type": "markdown", + "source": [ + "## Custom styles" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The visual appearance of wiring diagrams can be customized using the builtin\n", + "options or by redefining the TikZ styles for the boxes or wires." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"10\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", \"{rgb,255: red,230; green,230; blue,250}\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 22 + } + ], + "cell_type": "code", + "source": [ + "A, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)\n", + "f, g = Hom(:f, A, B), Hom(:g, B, A)\n", + "\n", + "pic = to_tikz(f⋅g, styles=Dict(\n", + " \"box\" => [\"draw\", \"fill\"=>\"{rgb,255: red,230; green,230; blue,250}\"],\n", + "))" + ], + "metadata": {}, + "execution_count": 22 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"7\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"variant junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-1.25\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"junction\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"0.5\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"1.25\", \"0\"), \"\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.west)+(-0.0,-1.5)\\$\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-150\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.-150\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.-30\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-30\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"\\$(root.east)+(0.0,-1.5)\\$\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", \"red\"), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"variant junction/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"fill\", \"blue\"), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ], + "cell_type": "code", + "source": [ + "X = Ob(FreeAbelianBicategoryRelations, :X)\n", + "\n", + "to_tikz(plus(X) ⋅ mcopy(X), styles=Dict(\n", + " \"junction\" => [\"circle\", \"draw\", \"fill\"=>\"red\", \"inner sep\"=>\"0\"],\n", + " \"variant junction\" => [\"circle\", \"draw\", \"fill\"=>\"blue\", \"inner sep\"=>\"0\"],\n", + "))" + ], + "metadata": {}, + "execution_count": 23 + }, + { + "cell_type": "markdown", + "source": [ + "By default, the boxes are rectangular (`:rectangle`). Other available shapes\n", + "include circles (`:circle`), ellipses (`:ellipse`), triangles (`:triangle`,\n", + "`:invtriangle`), and trapezoids (`:trapezium`, `:invtrapezium`)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"10\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circular box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circular box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.180\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.0\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"circular box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"circle\", nothing), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 24 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f⋅g, default_box_shape=:circle)" + ], + "metadata": {}, + "execution_count": 24 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"10\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"triangular box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"inverse triangular box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"inverse triangular box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"isosceles triangle\", nothing), Catlab.Graphics.TikZ.Property(\"isosceles triangle stretches\", nothing), Catlab.Graphics.TikZ.Property(\"shape border rotate\", \"0\"), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"sharp corners\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"triangular box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"isosceles triangle\", nothing), Catlab.Graphics.TikZ.Property(\"isosceles triangle stretches\", nothing), Catlab.Graphics.TikZ.Property(\"shape border rotate\", \"180\"), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"sharp corners\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 25 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f⋅g, rounded_boxes=false, box_shapes=Dict(\n", + " f => :triangle, g => :invtriangle,\n", + "))" + ], + "metadata": {}, + "execution_count": 25 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"4\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"10\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"triangular box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"2\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"inverse triangular box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"-2\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.north\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.north\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.south\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.north\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.south\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"-90\"), Catlab.Graphics.TikZ.Property(\"in\", \"90\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.south\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"inverse triangular box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"isosceles triangle\", nothing), Catlab.Graphics.TikZ.Property(\"isosceles triangle stretches\", nothing), Catlab.Graphics.TikZ.Property(\"shape border rotate\", \"270\"), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"sharp corners\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"triangular box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"isosceles triangle\", nothing), Catlab.Graphics.TikZ.Property(\"isosceles triangle stretches\", nothing), Catlab.Graphics.TikZ.Property(\"shape border rotate\", \"90\"), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"sharp corners\", nothing), Catlab.Graphics.TikZ.Property(\"inner sep\", \"0\")]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 26 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f⋅g, orientation=TopToBottom, rounded_boxes=false, box_shapes=Dict(\n", + " f => :triangle, g => :invtriangle,\n", + "))" + ], + "metadata": {}, + "execution_count": 26 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.TikZ.Document(Catlab.Graphics.TikZ.Picture(Catlab.Graphics.TikZ.Statement[Catlab.Graphics.TikZ.Node(\"root\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"outer box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum width\", \"10\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"minimum height\", \"4\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"0\", \"0\"), \"\"), Catlab.Graphics.TikZ.Node(\"n1\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"inverse trapezoidal box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"-2\", \"0\"), \"\\$f\\$\"), Catlab.Graphics.TikZ.Node(\"n2\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"trapezoidal box\", nothing), Catlab.Graphics.TikZ.Property(\"minimum size\", \"2\\\\tikzunit\")], Catlab.Graphics.TikZ.Coordinate(\"2\", \"0\"), \"\\$g\\$\"), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"root.west\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n1.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n1.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"-180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"n2.west\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)]), Catlab.Graphics.TikZ.Edge(Catlab.Graphics.TikZ.PathExpression[Catlab.Graphics.TikZ.NodeCoordinate(\"n2.east\"), Catlab.Graphics.TikZ.PathOperation(\"to\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"out\", \"0\"), Catlab.Graphics.TikZ.Property(\"in\", \"180\")]), Catlab.Graphics.TikZ.NodeCoordinate(\"root.east\")], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"wire\", nothing)])], Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"unit length/.code\", \"{{\\\\newdimen\\\\tikzunit}\\\\setlength{\\\\tikzunit}{#1}}\"), Catlab.Graphics.TikZ.Property(\"unit length\", \"4mm\"), Catlab.Graphics.TikZ.Property(\"x\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"y\", \"\\\\tikzunit\"), Catlab.Graphics.TikZ.Property(\"semithick\", nothing), Catlab.Graphics.TikZ.Property(\"inverse trapezoidal box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"trapezium\", nothing), Catlab.Graphics.TikZ.Property(\"trapezium angle\", \"80\"), Catlab.Graphics.TikZ.Property(\"trapezium stretches body\", nothing), Catlab.Graphics.TikZ.Property(\"shape border rotate\", \"270\"), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"outer box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", \"none\")]), Catlab.Graphics.TikZ.Property(\"trapezoidal box/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"trapezium\", nothing), Catlab.Graphics.TikZ.Property(\"trapezium angle\", \"80\"), Catlab.Graphics.TikZ.Property(\"trapezium stretches body\", nothing), Catlab.Graphics.TikZ.Property(\"shape border rotate\", \"90\"), Catlab.Graphics.TikZ.Property(\"draw\", nothing), Catlab.Graphics.TikZ.Property(\"solid\", nothing), Catlab.Graphics.TikZ.Property(\"rounded corners\", nothing)]), Catlab.Graphics.TikZ.Property(\"wire/.style\", Catlab.Graphics.TikZ.Property[Catlab.Graphics.TikZ.Property(\"draw\", nothing)])]), [\"calc\", \"shapes.geometric\"], [\"amssymb\"])", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 27 + } + ], + "cell_type": "code", + "source": [ + "to_tikz(f⋅g, box_shapes=Dict(\n", + " f => :invtrapezium, g => :trapezium,\n", + "))" + ], + "metadata": {}, + "execution_count": 27 + }, + { + "cell_type": "markdown", + "source": [ + "## Output formats" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The function `to_tikz` returns an object of type `TikZ.Document`, representing\n", + "a TikZ picture and its TikZ library dependencies as an abstract syntax tree.\n", + "When displayed interactively, this object is compiled by LaTeX to PDF and then\n", + "converted to SVG." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "To generate the LaTeX source code, use the builtin pretty-printer. This\n", + "feature does not require LaTeX or TikzPictures.jl to be installed." + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\usepackage{amssymb}\n", + "\\usetikzlibrary{calc}\n", + "\\usetikzlibrary{shapes.geometric}\n", + "\\begin{tikzpicture}[unit length/.code={{\\newdimen\\tikzunit}\\setlength{\\tikzunit}{#1}},unit length=4mm,x=\\tikzunit,y=\\tikzunit,semithick,box/.style={rectangle,draw,solid,rounded corners},outer box/.style={draw=none},wire/.style={draw}]\n", + " \\node[outer box,minimum width=10\\tikzunit,minimum height=4\\tikzunit] (root) at (0,0) {};\n", + " \\node[box,minimum size=2\\tikzunit] (n1) at (-2,0) {$f$};\n", + " \\node[box,minimum size=2\\tikzunit] (n2) at (2,0) {$g$};\n", + " \\path[wire] (root.west) to[out=0,in=-180] (n1.west);\n", + " \\path[wire] (n1.east) to[out=0,in=-180] (n2.west);\n", + " \\path[wire] (n2.east) to[out=0,in=180] (root.east);\n", + "\\end{tikzpicture}" + ] + } + ], + "cell_type": "code", + "source": [ + "import Catlab.Graphics: TikZ\n", + "\n", + "doc = to_tikz(f⋅g)\n", + "TikZ.pprint(doc)" + ], + "metadata": {}, + "execution_count": 28 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/02f20140.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/02f20140.svg new file mode 100644 index 000000000..2359d6e3c --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/02f20140.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/3c4a4940.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/3c4a4940.svg new file mode 100644 index 000000000..06a42992d --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/3c4a4940.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/83374daf.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/83374daf.svg new file mode 100644 index 000000000..cab20f04d --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/83374daf.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/86743e59.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/86743e59.svg new file mode 100644 index 000000000..ba9db4b02 --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/86743e59.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/8c31a7b8.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/8c31a7b8.svg new file mode 100644 index 000000000..d1c538c2b --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/8c31a7b8.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/8c4869d8.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/8c4869d8.svg new file mode 100644 index 000000000..fb5e752aa --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/8c4869d8.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/b9dd423d.svg b/v0.16.12/generated/graphics/tikz_wiring_diagrams/b9dd423d.svg new file mode 100644 index 000000000..0da768a2d --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/b9dd423d.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/graphics/tikz_wiring_diagrams/index.html b/v0.16.12/generated/graphics/tikz_wiring_diagrams/index.html new file mode 100644 index 000000000..9988064d5 --- /dev/null +++ b/v0.16.12/generated/graphics/tikz_wiring_diagrams/index.html @@ -0,0 +1,661 @@ + +Drawing wiring diagrams in TikZ · Catlab.jl

Drawing wiring diagrams in TikZ

Catlab can draw morphism expressions as TikZ pictures. To use this feature, LaTeX must be installed and the Julia package TikzPictures.jl must be loaded.

For best results, it is recommended to load the packages Convex.j and SCS.jl. When available they are used to optimize the layout of the outer ports.

using Catlab.WiringDiagrams, Catlab.Graphics
+
+import Convex, SCS
+import TikzPictures

Examples

Symmetric monoidal category

using Catlab.Theories
+
+A, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)
+f, g = Hom(:f, A, B), Hom(:g, B, A);

To start, here are a few very simple examples.

to_tikz(f, labels=true)
to_tikz(f⋅g, labels=true)
Example block output
to_tikz(f⊗g, labels=true, orientation=TopToBottom)
Example block output

Here is a more complex example, involving generators with compound domains and codomains.

h, k = Hom(:h, C, D),  Hom(:k, D, C)
+m, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)
+q = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)
+
+to_tikz((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))
Example block output

Identities and braidings appear as wires.

to_tikz(id(A), labels=true)
to_tikz(braid(A,B), labels=true, labels_pos=0.25)
to_tikz(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))

The isomorphism $A \otimes B \otimes C \to C \otimes B \otimes A$ induced by the permutation $(3\ 2\ 1)$ is a composite of braidings and identities.

σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))
+
+to_tikz(σ, arrowtip="Stealth", arrowtip_pos="-0.1pt",
+        labels=true, labels_pos="0.1pt")
Example block output

By default, anchor points are added along identity and braiding wires to reproduce the expression structure in the layout. The anchors can be disabled to get a more "unbiased" layout.

to_tikz(σ, anchor_wires=false, arrowtip="Stealth", arrowtip_pos="-0.1pt",
+        labels=true, labels_pos="0.1pt")
Example block output

Biproduct category

A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)
+f = Hom(:f, A, B)
+
+to_tikz(mcopy(A), labels=true)
to_tikz(delete(A), labels=true)
to_tikz(mcopy(A)⋅(f⊗f)⋅mmerge(B), labels=true)
Example block output
to_tikz(mcopy(A⊗B), orientation=TopToBottom, labels=true)
to_tikz(mcopy(A⊗B⊗C), orientation=TopToBottom, labels=true)
Example block output

Compact closed category

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

A, B = Ob(FreeCompactClosedCategory, :A, :B)
+
+to_tikz(dunit(A), arrowtip="Stealth", labels=true)
to_tikz(dcounit(A), arrowtip="Stealth", labels=true)

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:

A, B = Ob(FreeBicategoryRelations, :A, :B)
+f = Hom(:f, A, B)
+
+to_tikz((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))

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 \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)⊕swap(X,X)⊕id(X)) ⋅ (plus(X)⊕plus(X)))

Custom styles

The visual appearance of wiring diagrams can be customized using the builtin options or by redefining the TikZ styles for the boxes or wires.

A, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)
+f, g = Hom(:f, A, B), Hom(:g, B, A)
+
+pic = to_tikz(f⋅g, styles=Dict(
+  "box" => ["draw", "fill"=>"{rgb,255: red,230; green,230; blue,250}"],
+))
X = Ob(FreeAbelianBicategoryRelations, :X)
+
+to_tikz(plus(X) ⋅ mcopy(X), styles=Dict(
+  "junction" => ["circle", "draw", "fill"=>"red", "inner sep"=>"0"],
+  "variant junction" => ["circle", "draw", "fill"=>"blue", "inner sep"=>"0"],
+))

By default, the boxes are rectangular (:rectangle). Other available shapes include circles (:circle), ellipses (:ellipse), triangles (:triangle, :invtriangle), and trapezoids (:trapezium, :invtrapezium).

to_tikz(f⋅g, default_box_shape=:circle)
to_tikz(f⋅g, rounded_boxes=false, box_shapes=Dict(
+  f => :triangle, g => :invtriangle,
+))
to_tikz(f⋅g, orientation=TopToBottom, rounded_boxes=false, box_shapes=Dict(
+  f => :triangle, g => :invtriangle,
+))
to_tikz(f⋅g, box_shapes=Dict(
+  f => :invtrapezium, g => :trapezium,
+))

Output formats

The function to_tikz returns an object of type TikZ.Document, representing a TikZ picture and its TikZ library dependencies as an abstract syntax tree. When displayed interactively, this object is compiled by LaTeX to PDF and then converted to SVG.

To generate the LaTeX source code, use the builtin pretty-printer. This feature does not require LaTeX or TikzPictures.jl to be installed.

import Catlab.Graphics: TikZ
+
+doc = to_tikz(f⋅g)
+TikZ.pprint(doc)
\usepackage{amssymb}
+\usetikzlibrary{calc}
+\usetikzlibrary{shapes.geometric}
+\begin{tikzpicture}[unit length/.code={{\newdimen\tikzunit}\setlength{\tikzunit}{#1}},unit length=4mm,x=\tikzunit,y=\tikzunit,semithick,box/.style={rectangle,draw,solid,rounded corners},outer box/.style={draw=none},wire/.style={draw}]
+  \node[outer box,minimum width=10\tikzunit,minimum height=4\tikzunit] (root) at (0,0) {};
+  \node[box,minimum size=2\tikzunit] (n1) at (-2,0) {$f$};
+  \node[box,minimum size=2\tikzunit] (n2) at (2,0) {$g$};
+  \path[wire] (root.west) to[out=0,in=-180] (n1.west);
+  \path[wire] (n1.east) to[out=0,in=-180] (n2.west);
+  \path[wire] (n2.east) to[out=0,in=180] (root.east);
+\end{tikzpicture}
diff --git a/v0.16.12/generated/graphs/graphs.ipynb b/v0.16.12/generated/graphs/graphs.ipynb new file mode 100644 index 000000000..d301604ab --- /dev/null +++ b/v0.16.12/generated/graphs/graphs.ipynb @@ -0,0 +1,2083 @@ +{ + "cells": [ + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"V\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"E\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"tgt\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "V\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "E\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using GATlab, Catlab.Theories\n", + "using Catlab.CategoricalAlgebra\n", + "using Catlab.Graphs\n", + "using Catlab.Graphics\n", + "\n", + "draw(g; kw...) = to_graphviz(g; node_labels=true, edge_labels=true, kw...)\n", + "draw(f::ACSetTransformation; kw...) =\n", + " to_graphviz(f; node_labels=true, edge_labels=true, draw_codom=false, kw...)\n", + "\n", + "to_graphviz(SchGraph)" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "# The Category of Graphs\n", + "\n", + "The Theory of Graphs is given by the following Schema:\n", + "```julia\n", + "@present SchGraph(FreeSchema) begin\n", + " V::Ob\n", + " E::Ob\n", + " src::Hom(E,V)\n", + " tgt::Hom(E,V)\n", + "end" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "\"\"\" Abstract type for graphs, aka directed multigraphs.\n", + "\"\"\"\n", + "@abstract_acset_type AbstractGraph <: HasGraph" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "\"\"\" A graph, also known as a directed multigraph.\n", + "\"\"\"\n", + "@acset_type Graph(SchGraph, index=[:src,:tgt]) <: AbstractGraph\n", + "```\n", + "\n", + "That is all we need to do to generate the functor category [SchGraph, FinSet].\n", + "Catlab knows how to take a finitely presented category and generate all the data structures\n", + "that you need to represent functors into FinSet and natural transformations between those functors.\n", + "Note: the index=[:src, :tgt] keyword argument tells Catlab that you want to have an efficient index\n", + "the preimages of those morphisms. in this example, we want to be able to find the incoming and\n", + "outgoing edges of a vertex in O(1) time." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Creating some Graphs" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Once you have fixed the schema (aka indexing category or theory), you can make some instances.\n", + "Catlab has a DSL for specifying instances of any schema. It is called `@acset`.\n", + "In order to specify a Functor F=(F₀, F₁) into FinSet, you need to provide some data.\n", + " 1. For every A:Ob(C), you need F₀(A):FinSet\n", + " 2. For every f:A→B, you need to specify a FinFunction F₁(f):F₀(A)→F₀(B)\n", + "If the theory C has some equations, the data you provide would have to also satisfy those equations.\n", + "The theory of graphs has no equations, so there are no constraints on the data you provide,\n", + "except for those that come from functoriality." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "e = @acset Graph begin\n", + " V = 2\n", + " E = 1\n", + " src = [1]\n", + " tgt = [2]\n", + "end\n", + "\n", + "draw(e)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "a wedge is two edges that share a target" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n3->n2\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "w = @acset Graph begin\n", + " V = 3\n", + " E = 2\n", + " src=[1,3]\n", + " tgt=[2,2]\n", + "end\n", + "\n", + "draw(w)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "The CSet API generalizes the traditional Graph API" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "1-element Vector{Int64}:\n 2" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "parts(w, :V) # vertex set\n", + "\n", + "parts(w,:E) # edge set\n", + "\n", + "w[:src] # source map\n", + "\n", + "w[:tgt] # target map\n", + "\n", + "\n", + "incident(w, 1, :src) # edges out of vertex 1\n", + "\n", + "incident(w, 2, :tgt) # edges into vertex 2\n", + "\n", + "w[incident(w, 2, :tgt), :src] # vertices that are the source of edges whose target is vertex 2\n", + "\n", + "w[incident(w, 1, :src), :tgt] # vertices that are the target of edges whose src is vertex 1" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise:\n", + "1. Use the @acset macro to make a graph with at least 5 vertices\n", + "2. Draw the graph\n", + "3. Compute in neighbors and out neighbors and make sure they match your expectations.\n", + "4. Write a function that computes the 2-hop out-neighbors of a vertex." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "# Graph Homomorphisms\n", + "We can construct some graph homomorphisms between our two graphs.\n", + "What data do we need to specify?" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "ϕ = ACSetTransformation(e,w,E=[1], V=[1,2])\n", + "\n", + "is_natural(ϕ)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "The ACSetTransformation constructor does not automatically validate that the naturality squares commute!" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "false" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "ϕᵦ = ACSetTransformation(e,w,E=[1], V=[3,2])\n", + "is_natural(ϕᵦ)" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Our ϕᵦ in't natural because the edge map e₁ ↦ e₁ is not consistent with our vertex map, which sends v₁ ↦ v₃ and v₂ ↦ v₂. We can fix this by sending e₁ to e₂" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "ϕᵦ′ = ACSetTransformation(e,w,E=[2], V=[3,2])\n", + "is_natural(ϕᵦ′)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "So how does Catlab store the data of the natural transformation?\n", + "the domain" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Graph {V:2, E:1}\n┌───┬─────┬─────┐\n│\u001b[1m E │\u001b[1m src │\u001b[1m tgt │\n├───┼─────┼─────┤\n│\u001b[1m 1 │ 1 │ 2 │\n└───┴─────┴─────┘\n", + "text/html": [ + "
\n", + "Graph {V:2, E:1}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Esrctgt
112
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "ϕ.dom" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "the codomain" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Graph {V:3, E:2}\n┌───┬─────┬─────┐\n│\u001b[1m E │\u001b[1m src │\u001b[1m tgt │\n├───┼─────┼─────┤\n│\u001b[1m 1 │ 1 │ 2 │\n│\u001b[1m 2 │ 3 │ 2 │\n└───┴─────┴─────┘\n", + "text/html": [ + "
\n", + "Graph {V:3, E:2}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Esrctgt
112
232
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "ϕ.codom" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "the components" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(V = FinFunction([1, 2], 2, 3), E = FinFunction([1], 1, 2))" + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "ϕ.components" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "you can see the components using standard indexing notation with the object names. Notice that while CSets are indexed by morphisms, natural transformations are indexed by objects." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "FinFunction([1], 1, 2)" + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "ϕ[:V]\n", + "ϕ[:E]" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "We can check the naturality squares ourselves\n", + "The sources are preserved: `src ⋅ ϕᵥ == ϕₑ ⋅ src`" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "ϕ[:V](dom(ϕ)[:,:src]) == codom(ϕ)[collect(ϕ[:E]), :src]" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "The targets are preserved: `tgt ⋅ ϕᵥ == ϕₑ ⋅ tgt`" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "ϕ[:V](dom(ϕ)[:,:tgt]) == codom(ϕ)[collect(ϕ[:E]), :tgt]" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "This approach generalizes to the following:\n", + "\n", + "```julia\n", + "function is_natural(α::ACSetTransformation{S}) where {S}\n", + " X, Y = dom(α), codom(α)\n", + " for (f, c, d) in zip(hom(S), dom(S), codom(S))\n", + " Xf, Yf, α_c, α_d = subpart(X,f), subpart(Y,f), α[c], α[d]\n", + " all(Yf[α_c(i)] == α_d(Xf[i]) for i in eachindex(Xf)) || return false\n", + " end\n", + " return true\n", + "end\n", + "```\n", + "\n", + "Notice how we iterate over the homs in the schema category S `(f, c, d) in zip(hom(S), dom(S), codom(S))` We get one universally quantified equation `all(Yf[α_c(i)] == α_d(Xf[i]) for i in eachindex(Xf))` for each morphism in the indexing category\n", + "\n", + "### Exercise:\n", + "1. Take your graph from the previous exercise and construct a graph homomorphism from the wedge (w) into it.\n", + "2. Check that the naturality equations are satisfied.\n", + "3. Explain why we don't need to specify any data for the source and target morphisms in SchGraph when definining a graph homomorphism" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Finding Homomorphisms Automatically\n", + "As you saw in the previous exercise, constructing a natural transformation can be quite tedious. We want computers to automate tedious things for us. So we use an algorithm to enumerate all the homomorphisms between two CSets." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "CSet homomorphisms f:A→B are ways of finding a part of B that is shaped like A. You can view this as pattern matching. The graph A is the pattern and the graph B is the data. A morphism f:A→B is a collection of vertices and edges in B that is shaped like A. Note that you can ask Catlab to enforce constraints on the homomorphisms it will find including computing monic (injective) morphisms by passing the keyword `monic=true`. A monic morphism into B is a subobject of B. You can pass `iso=true` to get isomorphisms." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"9\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n1->n4\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n2->n6\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n6\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "t = @acset Graph begin\n", + " V = 3\n", + " E = 3\n", + " src = [1,2,1]\n", + " tgt = [2,3,3]\n", + "end\n", + "\n", + "draw(t)\n", + "\n", + "T = @acset Graph begin\n", + " V = 6\n", + " E = 9\n", + " src = [1,2,1, 3, 1,5,2,2,4]\n", + " tgt = [2,3,3, 4, 4,6,5,6,6]\n", + "end\n", + "\n", + "draw(T)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "The simplest pattern in a graph is just a single edge and each homomorphism ϕ:e→G is a single edge in G." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3" + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "length(homomorphisms(e, T, monic=true)) == nparts(T,:E) # number of edges\n", + "\n", + "\n", + "length(homomorphisms(t, T))" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "We can define this helper function to print out all the homomorphisms between graphs. Because all our graphs are simple, we only need to look at the vertex components." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3-element Vector{Vector{Int64}}:\n [1, 2, 3]\n [1, 3, 4]\n [2, 5, 6]" + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "graphhoms(g,h) = begin\n", + " map(homomorphisms(g,h)) do ϕ\n", + " collect(ϕ[:V])\n", + " end\n", + "end\n", + "\n", + "graphhoms(t, T)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "Homs ϕ:t→T are little triangles in T, but homs ϕ:T→t are colorings of T with 3 colors. The fact that there are edges in t that are missing, means that it provides constraints on what graphs have morphisms into it. For example, there are no morphisms T→t." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Any[]" + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "graphhoms(T, t)" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "The reason we don't have a morphism into t is vertices 2,3,4,5 aren't arranged into a triangle. We can relax those constraints by adding loops to the codomain. Loops in the codomain allow you to merge adjacent vertices when you construct the homomorphism." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n1->n1\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n2\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n3->n3\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "add_loops!(g) = add_parts!(g, :E, nparts(g,:V), src=parts(g,:V), tgt=parts(g,:V))\n", + "add_loops(g) = begin\n", + " h = copy(g)\n", + " add_loops!(h)\n", + " return h\n", + "end\n", + "\n", + "draw(add_loops(t))" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "cell_type": "markdown", + "source": [ + "Once we add loops, then we have morphisms." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "42" + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "length(homomorphisms(T,add_loops(t)))" + ], + "metadata": {}, + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "## Bipartite Graphs\n", + "Many computer science problems involve graphs that have two types of vertices. For example, when matching students to classes, you might represent the students as one type of vertex and the classes as another type of vertex. Then the edges (s,c) represent \"student s is enrolled in class c\". In this scenario there can be no edges from a class vertex to another class vertex, or from a student vertex to a student vertex. Graphs for which there exists such a classification are called bipartite graphs. In Category Theory, we shift from thinking about graphs with properties to graph homomorphisms that witness that property and think of bipartitioned graphs." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "First we construct a bipartite graph:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ], + "cell_type": "code", + "source": [ + "sq = apex(product(add_loops(e), add_loops(e)))\n", + "rem_parts!(sq, :E, [1,5,6,8,9])\n", + "draw(sq)" + ], + "metadata": {}, + "execution_count": 20 + }, + { + "cell_type": "markdown", + "source": [ + "We will use the symmetric edge graph to identify the bipartitions of this graph." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"2\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2->dom_1\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ], + "cell_type": "code", + "source": [ + "esym = @acset Graph begin\n", + " V = 2\n", + " E = 2\n", + " src = [1,2]\n", + " tgt = [2,1]\n", + "end\n", + "\n", + "draw(id(esym))" + ], + "metadata": {}, + "execution_count": 21 + }, + { + "cell_type": "markdown", + "source": [ + "There are two ways to bipartition sq." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{Vector{Int64}}:\n [1, 2, 2, 1]\n [2, 1, 1, 2]" + }, + "metadata": {}, + "execution_count": 22 + } + ], + "cell_type": "code", + "source": [ + "graphhoms(sq, esym)" + ], + "metadata": {}, + "execution_count": 22 + }, + { + "cell_type": "markdown", + "source": [ + "This comes from the fact that esym has 2 automorphisms!" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{Vector{Int64}}:\n [1, 2]\n [2, 1]" + }, + "metadata": {}, + "execution_count": 23 + } + ], + "cell_type": "code", + "source": [ + "graphhoms(esym, esym)" + ], + "metadata": {}, + "execution_count": 23 + }, + { + "cell_type": "markdown", + "source": [ + "the first coloring" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_1->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_2->dom_4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 24 + } + ], + "cell_type": "code", + "source": [ + "draw(homomorphisms(sq, esym)[1])" + ], + "metadata": {}, + "execution_count": 24 + }, + { + "cell_type": "markdown", + "source": [ + "but we can also swap the roles of the colors" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_1->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_2->dom_4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 25 + } + ], + "cell_type": "code", + "source": [ + "draw(homomorphisms(sq, esym)[2])" + ], + "metadata": {}, + "execution_count": 25 + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise:\n", + "1. Construct a graph representation of a checkerboard\n", + "2. Draw the two bipartitions of the checkerboard" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "We can generalize the notion of Bipartite graph to any number of parts. I like to call Kₖ the k-coloring classifier because homomorphims into α:G → Kₖ are k-colorings of G." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BFFF\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#AE7BFF\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#BF9A00\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FF00A2\", :label => \"6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_1->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_2->dom_1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_3->dom_1\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "dom_3->dom_2\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 26 + } + ], + "cell_type": "code", + "source": [ + "clique(k::Int) = begin\n", + " Kₖ = Graph(k)\n", + " for i in 1:k\n", + " for j in 1:k\n", + " if j ≠ i\n", + " add_parts!(Kₖ, :E, 1, src=i, tgt=j)\n", + " end\n", + " end\n", + " end\n", + " return Kₖ\n", + "end\n", + "\n", + "K₃ = clique(3)\n", + "draw(id(K₃))" + ], + "metadata": {}, + "execution_count": 26 + }, + { + "cell_type": "markdown", + "source": [ + "Our graph T is not 2-colorable," + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "0" + }, + "metadata": {}, + "execution_count": 27 + } + ], + "cell_type": "code", + "source": [ + "length(homomorphisms(T, esym))" + ], + "metadata": {}, + "execution_count": 27 + }, + { + "cell_type": "markdown", + "source": [ + "but we can use 3 colors to color T." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"dom_5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"dom_6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#AE7BFF\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FF00A2\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BFFF\", :label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#AE7BFF\", :label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#AE7BFF\", :label => \"9\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_1->dom_3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_1->dom_4\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "dom_2->dom_5\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "dom_6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "dom_2->dom_6\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "dom_3->dom_4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_4->dom_6\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "dom_5->dom_6\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 28 + } + ], + "cell_type": "code", + "source": [ + "draw(homomorphism(T, K₃))" + ], + "metadata": {}, + "execution_count": 28 + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise:\n", + "1. Find a graph that is not 3-colorable\n", + "2. Find a graph that is not 4-colorable" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Homomorphisms in [C, Set] are like Types\n", + "Any graph can play the role of the codomain. If you pick a graph that is incomplete, you get a more constrained notion of coloring where there are color combinations that are forbidden." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BFFF\", :label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_3->dom_1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 29 + } + ], + "cell_type": "code", + "source": [ + "triloop = @acset Graph begin\n", + " V = 3\n", + " E = 3\n", + " src = [1,2,3]\n", + " tgt = [2,3,1]\n", + "end\n", + "\n", + "draw(id(triloop))" + ], + "metadata": {}, + "execution_count": 29 + }, + { + "cell_type": "markdown", + "source": [ + "With this graph, we can pick out directed 3-cycles in a graph like T2," + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "9-element Vector{Vector{Int64}}:\n [1, 2, 3, 1, 2, 3]\n [1, 2, 3, 2, 3, 1]\n [1, 2, 3, 3, 1, 2]\n [2, 3, 1, 1, 2, 3]\n [2, 3, 1, 2, 3, 1]\n [2, 3, 1, 3, 1, 2]\n [3, 1, 2, 1, 2, 3]\n [3, 1, 2, 2, 3, 1]\n [3, 1, 2, 3, 1, 2]" + }, + "metadata": {}, + "execution_count": 30 + } + ], + "cell_type": "code", + "source": [ + "T2 = @acset Graph begin\n", + " V = 6\n", + " E = 6\n", + " src = [1,2,3,4,5,6]\n", + " tgt = [2,3,1,5,6,4]\n", + "end\n", + "graphhoms(T2, triloop)" + ], + "metadata": {}, + "execution_count": 30 + }, + { + "cell_type": "markdown", + "source": [ + "and we can draw those cyclic roles with colors" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3-element Vector{Vector{Int64}}:\n [1, 2, 3, 3, 1, 2]\n [2, 3, 1, 1, 2, 3]\n [3, 1, 2, 2, 3, 1]" + }, + "metadata": {}, + "execution_count": 31 + } + ], + "cell_type": "code", + "source": [ + "draw(homomorphisms(T2, triloop)[1])\n", + "\n", + "T3 = @acset Graph begin\n", + " V = 6\n", + " E = 7\n", + " src = [1,2,3,4,5,6, 2]\n", + " tgt = [2,3,1,5,6,4, 4]\n", + "end\n", + "graphhoms(T3, triloop)" + ], + "metadata": {}, + "execution_count": 31 + }, + { + "cell_type": "markdown", + "source": [ + "Using the colors as shown:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BFFF\", :label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_3->dom_1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 32 + } + ], + "cell_type": "code", + "source": [ + "draw(id(triloop))" + ], + "metadata": {}, + "execution_count": 32 + }, + { + "cell_type": "markdown", + "source": [ + "We can see our coloring of T3:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"hom_graph\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"dom_1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"dom_2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"dom_3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"dom_4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#008C00\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"dom_5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C721DD\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"dom_6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#D14A00\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BFFF\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BFFF\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#F8766D\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"dom_2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"dom_4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#00BB20\", :label => \"7\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "hom_graph\n", + "\n", + "\n", + "\n", + "dom_1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_1->dom_2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "dom_3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_2->dom_3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "dom_4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_2->dom_4\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "dom_3->dom_1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "dom_5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "dom_4->dom_5\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "dom_6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "dom_5->dom_6\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "dom_6->dom_4\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 33 + } + ], + "cell_type": "code", + "source": [ + "draw(homomorphisms(T3, triloop)[1])" + ], + "metadata": {}, + "execution_count": 33 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphs/graphs/index.html b/v0.16.12/generated/graphs/graphs/index.html new file mode 100644 index 000000000..2b867e203 --- /dev/null +++ b/v0.16.12/generated/graphs/graphs/index.html @@ -0,0 +1,1125 @@ + +The Category of Graphs · Catlab.jl
using GATlab, Catlab.Theories
+using Catlab.CategoricalAlgebra
+using Catlab.Graphs
+using Catlab.Graphics
+
+draw(g; kw...) = to_graphviz(g; node_labels=true, edge_labels=true, kw...)
+draw(f::ACSetTransformation; kw...) =
+  to_graphviz(f; node_labels=true, edge_labels=true, draw_codom=false, kw...)
+
+to_graphviz(SchGraph)

The Category of Graphs

The Theory of Graphs is given by the following Schema:

@present SchGraph(FreeSchema) begin
+  V::Ob
+  E::Ob
+  src::Hom(E,V)
+  tgt::Hom(E,V)
+end
+
+""" Abstract type for graphs, aka directed multigraphs.
+"""
+@abstract_acset_type AbstractGraph <: HasGraph
+
+""" A graph, also known as a directed multigraph.
+"""
+@acset_type Graph(SchGraph, index=[:src,:tgt]) <: AbstractGraph

That is all we need to do to generate the functor category [SchGraph, FinSet]. Catlab knows how to take a finitely presented category and generate all the data structures that you need to represent functors into FinSet and natural transformations between those functors. Note: the index=[:src, :tgt] keyword argument tells Catlab that you want to have an efficient index the preimages of those morphisms. in this example, we want to be able to find the incoming and outgoing edges of a vertex in O(1) time.

Creating some Graphs

Once you have fixed the schema (aka indexing category or theory), you can make some instances. Catlab has a DSL for specifying instances of any schema. It is called @acset. In order to specify a Functor F=(F₀, F₁) into FinSet, you need to provide some data. 1. For every A:Ob(C), you need F₀(A):FinSet 2. For every f:A→B, you need to specify a FinFunction F₁(f):F₀(A)→F₀(B) If the theory C has some equations, the data you provide would have to also satisfy those equations. The theory of graphs has no equations, so there are no constraints on the data you provide, except for those that come from functoriality.

e = @acset Graph begin
+    V = 2
+    E = 1
+    src = [1]
+    tgt = [2]
+end
+
+draw(e)

a wedge is two edges that share a target

w = @acset Graph begin
+    V = 3
+    E = 2
+    src=[1,3]
+    tgt=[2,2]
+end
+
+draw(w)

The CSet API generalizes the traditional Graph API

parts(w, :V)  # vertex set
+
+parts(w,:E) # edge set
+
+w[:src] # source map
+
+w[:tgt] # target map
+
+
+incident(w, 1, :src) # edges out of vertex 1
+
+incident(w, 2, :tgt) # edges into vertex 2
+
+w[incident(w, 2, :tgt), :src] # vertices that are the source of edges whose target is vertex 2
+
+w[incident(w, 1, :src), :tgt] # vertices that are the target of edges whose src is vertex 1
1-element Vector{Int64}:
+ 2

Exercise:

  1. Use the @acset macro to make a graph with at least 5 vertices
  2. Draw the graph
  3. Compute in neighbors and out neighbors and make sure they match your expectations.
  4. Write a function that computes the 2-hop out-neighbors of a vertex.

Graph Homomorphisms

We can construct some graph homomorphisms between our two graphs. What data do we need to specify?

ϕ = ACSetTransformation(e,w,E=[1], V=[1,2])
+
+is_natural(ϕ)
true

The ACSetTransformation constructor does not automatically validate that the naturality squares commute!

ϕᵦ = ACSetTransformation(e,w,E=[1], V=[3,2])
+is_natural(ϕᵦ)
false

Our ϕᵦ in't natural because the edge map e₁ ↦ e₁ is not consistent with our vertex map, which sends v₁ ↦ v₃ and v₂ ↦ v₂. We can fix this by sending e₁ to e₂

ϕᵦ′ = ACSetTransformation(e,w,E=[2], V=[3,2])
+is_natural(ϕᵦ′)
true

So how does Catlab store the data of the natural transformation? the domain

ϕ.dom
+Graph {V:2, E:1} + + + + + + + + + + + + + + + +
Esrctgt
112
+
+

the codomain

ϕ.codom
+Graph {V:3, E:2} + + + + + + + + + + + + + + + + + + + + +
Esrctgt
112
232
+
+

the components

ϕ.components
(V = FinFunction([1, 2], 2, 3), E = FinFunction([1], 1, 2))

you can see the components using standard indexing notation with the object names. Notice that while CSets are indexed by morphisms, natural transformations are indexed by objects.

ϕ[:V]
+ϕ[:E]
FinFunction([1], 1, 2)

We can check the naturality squares ourselves The sources are preserved: src ⋅ ϕᵥ == ϕₑ ⋅ src

ϕ[:V](dom(ϕ)[:,:src]) == codom(ϕ)[collect(ϕ[:E]), :src]
true

The targets are preserved: tgt ⋅ ϕᵥ == ϕₑ ⋅ tgt

ϕ[:V](dom(ϕ)[:,:tgt]) == codom(ϕ)[collect(ϕ[:E]), :tgt]
true

This approach generalizes to the following:

function is_natural(α::ACSetTransformation{S}) where {S}
+   X, Y = dom(α), codom(α)
+   for (f, c, d) in zip(hom(S), dom(S), codom(S))
+     Xf, Yf, α_c, α_d = subpart(X,f), subpart(Y,f), α[c], α[d]
+     all(Yf[α_c(i)] == α_d(Xf[i]) for i in eachindex(Xf)) || return false
+   end
+   return true
+end

Notice how we iterate over the homs in the schema category S (f, c, d) in zip(hom(S), dom(S), codom(S)) We get one universally quantified equation all(Yf[α_c(i)] == α_d(Xf[i]) for i in eachindex(Xf)) for each morphism in the indexing category

Exercise:

  1. Take your graph from the previous exercise and construct a graph homomorphism from the wedge (w) into it.
  2. Check that the naturality equations are satisfied.
  3. Explain why we don't need to specify any data for the source and target morphisms in SchGraph when definining a graph homomorphism

Finding Homomorphisms Automatically

As you saw in the previous exercise, constructing a natural transformation can be quite tedious. We want computers to automate tedious things for us. So we use an algorithm to enumerate all the homomorphisms between two CSets.

CSet homomorphisms f:A→B are ways of finding a part of B that is shaped like A. You can view this as pattern matching. The graph A is the pattern and the graph B is the data. A morphism f:A→B is a collection of vertices and edges in B that is shaped like A. Note that you can ask Catlab to enforce constraints on the homomorphisms it will find including computing monic (injective) morphisms by passing the keyword monic=true. A monic morphism into B is a subobject of B. You can pass iso=true to get isomorphisms.

t = @acset Graph begin
+    V = 3
+    E = 3
+    src = [1,2,1]
+    tgt = [2,3,3]
+end
+
+draw(t)
+
+T = @acset Graph begin
+    V = 6
+    E = 9
+    src = [1,2,1, 3, 1,5,2,2,4]
+    tgt = [2,3,3, 4, 4,6,5,6,6]
+end
+
+draw(T)

The simplest pattern in a graph is just a single edge and each homomorphism ϕ:e→G is a single edge in G.

length(homomorphisms(e, T, monic=true)) == nparts(T,:E) # number of edges
+
+
+length(homomorphisms(t, T))
3

We can define this helper function to print out all the homomorphisms between graphs. Because all our graphs are simple, we only need to look at the vertex components.

graphhoms(g,h) = begin
+    map(homomorphisms(g,h)) do ϕ
+        collect(ϕ[:V])
+    end
+end
+
+graphhoms(t, T)
3-element Vector{Vector{Int64}}:
+ [1, 2, 3]
+ [1, 3, 4]
+ [2, 5, 6]

Homs ϕ:t→T are little triangles in T, but homs ϕ:T→t are colorings of T with 3 colors. The fact that there are edges in t that are missing, means that it provides constraints on what graphs have morphisms into it. For example, there are no morphisms T→t.

graphhoms(T, t)
Any[]

The reason we don't have a morphism into t is vertices 2,3,4,5 aren't arranged into a triangle. We can relax those constraints by adding loops to the codomain. Loops in the codomain allow you to merge adjacent vertices when you construct the homomorphism.

add_loops!(g) = add_parts!(g, :E, nparts(g,:V), src=parts(g,:V), tgt=parts(g,:V))
+add_loops(g) = begin
+    h = copy(g)
+    add_loops!(h)
+    return h
+end
+
+draw(add_loops(t))

Once we add loops, then we have morphisms.

length(homomorphisms(T,add_loops(t)))
42

Bipartite Graphs

Many computer science problems involve graphs that have two types of vertices. For example, when matching students to classes, you might represent the students as one type of vertex and the classes as another type of vertex. Then the edges (s,c) represent "student s is enrolled in class c". In this scenario there can be no edges from a class vertex to another class vertex, or from a student vertex to a student vertex. Graphs for which there exists such a classification are called bipartite graphs. In Category Theory, we shift from thinking about graphs with properties to graph homomorphisms that witness that property and think of bipartitioned graphs.

First we construct a bipartite graph:

sq = apex(product(add_loops(e), add_loops(e)))
+rem_parts!(sq, :E, [1,5,6,8,9])
+draw(sq)

We will use the symmetric edge graph to identify the bipartitions of this graph.

esym = @acset Graph begin
+    V = 2
+    E = 2
+    src = [1,2]
+    tgt = [2,1]
+end
+
+draw(id(esym))

There are two ways to bipartition sq.

graphhoms(sq, esym)
2-element Vector{Vector{Int64}}:
+ [1, 2, 2, 1]
+ [2, 1, 1, 2]

This comes from the fact that esym has 2 automorphisms!

graphhoms(esym, esym)
2-element Vector{Vector{Int64}}:
+ [1, 2]
+ [2, 1]

the first coloring

draw(homomorphisms(sq, esym)[1])

but we can also swap the roles of the colors

draw(homomorphisms(sq, esym)[2])

Exercise:

  1. Construct a graph representation of a checkerboard
  2. Draw the two bipartitions of the checkerboard

We can generalize the notion of Bipartite graph to any number of parts. I like to call Kₖ the k-coloring classifier because homomorphims into α:G → Kₖ are k-colorings of G.

clique(k::Int) = begin
+    Kₖ = Graph(k)
+    for i in 1:k
+        for j in 1:k
+            if j ≠ i
+                add_parts!(Kₖ, :E, 1, src=i, tgt=j)
+            end
+        end
+    end
+    return Kₖ
+end
+
+K₃ = clique(3)
+draw(id(K₃))

Our graph T is not 2-colorable,

length(homomorphisms(T, esym))
0

but we can use 3 colors to color T.

draw(homomorphism(T, K₃))

Exercise:

  1. Find a graph that is not 3-colorable
  2. Find a graph that is not 4-colorable

Homomorphisms in [C, Set] are like Types

Any graph can play the role of the codomain. If you pick a graph that is incomplete, you get a more constrained notion of coloring where there are color combinations that are forbidden.

triloop = @acset Graph begin
+    V = 3
+    E = 3
+    src = [1,2,3]
+    tgt = [2,3,1]
+end
+
+draw(id(triloop))

With this graph, we can pick out directed 3-cycles in a graph like T2,

T2 = @acset Graph begin
+    V = 6
+    E = 6
+    src = [1,2,3,4,5,6]
+    tgt = [2,3,1,5,6,4]
+end
+graphhoms(T2, triloop)
9-element Vector{Vector{Int64}}:
+ [1, 2, 3, 1, 2, 3]
+ [1, 2, 3, 2, 3, 1]
+ [1, 2, 3, 3, 1, 2]
+ [2, 3, 1, 1, 2, 3]
+ [2, 3, 1, 2, 3, 1]
+ [2, 3, 1, 3, 1, 2]
+ [3, 1, 2, 1, 2, 3]
+ [3, 1, 2, 2, 3, 1]
+ [3, 1, 2, 3, 1, 2]

and we can draw those cyclic roles with colors

draw(homomorphisms(T2, triloop)[1])
+
+T3 = @acset Graph begin
+    V = 6
+    E = 7
+    src = [1,2,3,4,5,6, 2]
+    tgt = [2,3,1,5,6,4, 4]
+end
+graphhoms(T3, triloop)
3-element Vector{Vector{Int64}}:
+ [1, 2, 3, 3, 1, 2]
+ [2, 3, 1, 1, 2, 3]
+ [3, 1, 2, 2, 3, 1]

Using the colors as shown:

draw(id(triloop))

We can see our coloring of T3:

draw(homomorphisms(T3, triloop)[1])
diff --git a/v0.16.12/generated/graphs/graphs_label.ipynb b/v0.16.12/generated/graphs/graphs_label.ipynb new file mode 100644 index 000000000..8949d15a2 --- /dev/null +++ b/v0.16.12/generated/graphs/graphs_label.ipynb @@ -0,0 +1,2474 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Labeled Graphs\n", + "This example demonstrates how to define new C-Sets from existing C-Sets via the example of adding labels to a graph. We treat labels as members of an arbitrary FinSet of labels rather than a data attribute for pedagogical reasons. When you think of graphs where the labels are numbers, colors, or values of some kind, you would want to make them attributes. The motivation for this example is to be the simplest extension to the theory of graphs that you could possibly make." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "draw (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Theories, Catlab.CategoricalAlgebra\n", + "using Catlab.Graphs, Catlab.Graphics\n", + "\n", + "using Colors\n", + "draw(g) = to_graphviz(g, node_labels=true, edge_labels=true)" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "We start with the theory of graphs, which is copied from `Catlab.Graphs.BasicGraphs`. The two objects are the edges and vertices and we have two functions `src,tgt` that assign to every edge the source vertex and target vertex respectively. Functors from this category to Set (diagrams in Set of this shape) are category theoretic graphs (directed multigraphs)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"V\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"E\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"tgt\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "V\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "E\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "@present SchGraph(FreeSchema) begin\n", + " V::Ob\n", + " E::Ob\n", + " src::Hom(E,V)\n", + " tgt::Hom(E,V)\n", + "end\n", + "\n", + "to_graphviz(SchGraph)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "To the theory of graphs we want to add a set of labels `L` and map that assigns to every vertex to its label in `L`." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"V\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"E\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"L\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"label\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "V\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "L\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "label\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "E\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "@present SchLGraph <: SchGraph begin\n", + " L::Ob\n", + " label::Hom(V,L)\n", + "end\n", + "\n", + "to_graphviz(SchLGraph)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Catlab will automatically generate all the data structure and algorithms (storing, mutating, serializing, etc.) our `LGraphs` for us. This snippet declares that the Julia type `LGraph` should be composed of objects of the functor category `SchLGraph → Skel(FinSet)`, where `Skel(FinSet)` is the subcategory of Set containing finite sets of form `1:n`. We want our Julia type `LGraph` to inherit from the type `AbstractGraph` so that we can run graph algorithms on it. And we want the generated data structures to make an index of the maps `src`, `tgt`, and `label` so that looking up the in and outneighbors of vertex is fast and accessing all vertices by label is also fast.\n", + "\n", + "**Note**: This schema differs from that of `LabeledGraph` in `Catlab.Graphs` by making the label type an object (`Ob`) rather than attribute type (`AttrType`). In this case, the set of labels can vary from instance to instance and homomorphisms can rename labels; in the other case, the set of labels is fixed by a Julia type, such as `Int` or `Symbol`, and label values must be strictly preserved homomorphisms. The graph theory literature does not always distinguish very carefully between these two cases." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Main.var\"##238\".LGraph" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "@acset_type LGraph(SchLGraph, index=[:src,:tgt,:label]) <: AbstractGraph" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "We need to tell Catlab how to convert our `LGraph` type into the normal `Graph` type by taking just the edges and vertices. This could be computed with Functorial Data Migration, but that is left for another sketch." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "to_graph (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "to_graph(g::LGraph) = begin\n", + " h = Graph(nparts(g,:V))\n", + " for e in edges(g)\n", + " add_edge!(h, g[e, :src], g[e,:tgt])\n", + " end\n", + " return h\n", + "end" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Graphviz doesn't automatically know how we want to draw the labels, so we have to explicitly provide code that converts them to colors on the vertices. Note that we aren't calling these colored graphs, because that would imply some connectivity constraints on which vertices are allowed to be colored with the same colors. These labels are arbitrary, but we use color to visually encode them." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "draw (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "GraphvizGraphs.to_graphviz(g::LGraph; kw...) =\n", + " to_graphviz(to_graphviz_property_graph(g; kw...))\n", + "\n", + "function GraphvizGraphs.to_graphviz_property_graph(g::LGraph; kw...)\n", + " h = to_graph(g)\n", + " pg = to_graphviz_property_graph(h; kw...)\n", + " vcolors = hex.(range(colorant\"#0021A5\", stop=colorant\"#FA4616\", length=nparts(g, :L)))\n", + " for v in vertices(g)\n", + " l = g[v, :label]\n", + " set_vprops!(pg, v, Dict(:color => \"#$(vcolors[l])\"))\n", + " end\n", + " pg\n", + "end\n", + "\n", + "draw(G::LGraph) = to_graphviz(G, node_labels=true, edge_labels=true)" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "Now we can start making some `LGraph` instances." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#532D75\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A73A46\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "G = @acset LGraph begin\n", + " V = 4\n", + " E = 4\n", + " L = 4\n", + " src = [1,1,2,3]\n", + " tgt = [2,3,4,4]\n", + " label = [1,2,3,4]\n", + "end\n", + "\n", + "draw(G)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "The graph `G` has a 1-1 map between vertices and labels. That isn't necessary." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "H = @acset LGraph begin\n", + " V = 4\n", + " E = 4\n", + " L = 3\n", + " src = [1,1,2,3]\n", + " tgt = [2,3,4,4]\n", + " label = [1,2,2,3]\n", + "end\n", + "\n", + "draw(H)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "We can look at some homomorphisms from G to H by their action on the labels or on the vertices." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "homsₗ (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(G,H) = map(α -> α[:V], homomorphisms(G, H))\n", + "homsₗ(G,H) = map(α -> α[:L], homomorphisms(G, H))" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "αₗ: G→ H" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "4-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 3], 4, 3)\n FinFunction([1, 2, 2, 3], 4, 3)\n FinFunction([1, 2, 2, 3], 4, 3)\n FinFunction([1, 2, 2, 3], 4, 3)" + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "homsₗ(G,H)" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "αᵥ: G→ H" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "4-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4], 4, 4)\n FinFunction([1, 2, 3, 4], 4, 4)\n FinFunction([1, 3, 2, 4], 4, 4)\n FinFunction([1, 3, 3, 4], 4, 4)" + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(G,H)" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "Note that if we reverse the direction of our homomorphism search, we get fewer matches even though the two `LGraph`s are isomorphic as graphs. The fact that in `H` vertex two and three are the same label means we have to send them to the same vertex in `G`." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4], 4, 4)\n FinFunction([1, 3, 3, 4], 4, 4)" + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(H,G)" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "We can build some bigger examples like A." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n4->n6\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "A = @acset LGraph begin\n", + " V = 6\n", + " E = 7\n", + " L = 3\n", + " src = [1,1,2,3,2,5,4]\n", + " tgt = [2,3,4,4,5,6,6]\n", + " label = [1,2,2,3,2,3]\n", + "end\n", + "draw(A)" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "and B." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#532D75\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A73A46\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#532D75\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A73A46\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n4->n6\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "B = @acset LGraph begin\n", + " V = 6\n", + " E = 7\n", + " L = 4\n", + " src = [1,1,2,3,2,5,4]\n", + " tgt = [2,3,4,4,5,6,6]\n", + " label = [1,2,4,3,2,3]\n", + "end\n", + "draw(B)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "The morphisms from A to B and B to A are also different, showing how the labels affect the structure in this category." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "1-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4, 5, 6], 6, 6)" + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(A,B)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "There are more morphisms from B to A than A to B." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4, 5, 6], 6, 6)\n FinFunction([1, 2, 3, 4, 5, 6], 6, 6)" + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(B,A)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "There are two automorphisms on A" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4, 5, 6], 6, 6)\n FinFunction([1, 2, 3, 4, 5, 6], 6, 6)" + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(A,A)" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "And two automorphisms on B" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4, 5, 6], 6, 6)\n FinFunction([1, 2, 3, 4, 5, 6], 6, 6)" + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "homsᵥ(B,B)" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "cell_type": "markdown", + "source": [ + "But if we forget about the labels and look at the automorphisms of the underlying graph, we get more automorphisms!" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "8-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:\n FinFunction([1, 2, 2, 4, 4, 6], 6, 6)\n FinFunction([1, 2, 2, 4, 5, 6], 6, 6)\n FinFunction([1, 2, 2, 5, 4, 6], 6, 6)\n FinFunction([1, 2, 2, 5, 5, 6], 6, 6)\n FinFunction([1, 2, 3, 4, 4, 6], 6, 6)\n FinFunction([1, 2, 3, 4, 5, 6], 6, 6)\n FinFunction([1, 3, 2, 4, 4, 6], 6, 6)\n FinFunction([1, 3, 3, 4, 4, 6], 6, 6)" + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "A₀ = to_graph(A)\n", + "homsᵥ(A₀, A₀)" + ], + "metadata": {}, + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "## Limits and Composition by Multiplication\n", + "Catlab has an implementation of limits for any C-Sets over any schema. So, we can just ask about labeled graphs. Notice that we get more distinct colors in the product than in either initial graph. This is because the labels of the product are pairs of labels from the factors. If `G` has `n` colors and `H` has `m` colors `G×H` will have `n×m` colors." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#11239B\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#212692\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#322888\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#432B7F\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#532D75\", :label => \"6\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#64306C\", :label => \"7\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#753262\", :label => \"8\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#853559\", :label => \"9\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#96374F\", :label => \"10\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n12\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n12\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n14\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n15\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"10\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"11\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"12\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n14\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"13\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n15\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"14\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"15\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"16\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n1->n6\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n1->n7\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n1->n10\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n11\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n1->n11\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n2->n8\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n12\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n2->n12\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n3->n12\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n14\n", + "\n", + "14\n", + "\n", + "\n", + "\n", + "n5->n14\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n15\n", + "\n", + "15\n", + "\n", + "\n", + "\n", + "n5->n15\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n16\n", + "\n", + "16\n", + "\n", + "\n", + "\n", + "n6->n16\n", + "\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n7->n16\n", + "\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n9->n14\n", + "\n", + "\n", + "13\n", + "\n", + "\n", + "\n", + "n9->n15\n", + "\n", + "\n", + "14\n", + "\n", + "\n", + "\n", + "n10->n16\n", + "\n", + "\n", + "15\n", + "\n", + "\n", + "\n", + "n11->n16\n", + "\n", + "\n", + "16\n", + "\n", + "\n", + "\n", + "n13\n", + "\n", + "13\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ], + "cell_type": "code", + "source": [ + "draw(apex(product(G,G)))" + ], + "metadata": {}, + "execution_count": 20 + }, + { + "cell_type": "markdown", + "source": [ + "The graph above looks weirdly disconnected and probably wasn't what you expected to see as the product. When we compose with products, we often want to add the reflexive edges in order to get the expected notion of product." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#11239B\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#212692\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#322888\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#432B7F\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#532D75\", :label => \"6\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#64306C\", :label => \"7\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#753262\", :label => \"8\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#853559\", :label => \"9\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#96374F\", :label => \"10\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n15\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"23\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"24\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n14\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"25\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n15\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"26\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"27\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"28\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n13\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"29\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n14\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"30\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n15\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"31\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n12\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n16\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"32\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n1->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n1->n6\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n1->n7\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n1->n9\n", + "\n", + "\n", + "13\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n1->n10\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n11\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n1->n11\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n2->n6\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n2->n8\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n10\n", + "\n", + "\n", + "14\n", + "\n", + "\n", + "\n", + "n12\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n2->n12\n", + "\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n3->n7\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n3->n11\n", + "\n", + "\n", + "15\n", + "\n", + "\n", + "\n", + "n3->n12\n", + "\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n8\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n4->n12\n", + "\n", + "\n", + "16\n", + "\n", + "\n", + "\n", + "n13\n", + "\n", + "13\n", + "\n", + "\n", + "\n", + "n5->n13\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "n14\n", + "\n", + "14\n", + "\n", + "\n", + "\n", + "n5->n14\n", + "\n", + "\n", + "17\n", + "\n", + "\n", + "\n", + "n15\n", + "\n", + "15\n", + "\n", + "\n", + "\n", + "n5->n15\n", + "\n", + "\n", + "18\n", + "\n", + "\n", + "\n", + "n6->n14\n", + "\n", + "\n", + "22\n", + "\n", + "\n", + "\n", + "n16\n", + "\n", + "16\n", + "\n", + "\n", + "\n", + "n6->n16\n", + "\n", + "\n", + "19\n", + "\n", + "\n", + "\n", + "n7->n15\n", + "\n", + "\n", + "23\n", + "\n", + "\n", + "\n", + "n7->n16\n", + "\n", + "\n", + "20\n", + "\n", + "\n", + "\n", + "n8->n16\n", + "\n", + "\n", + "24\n", + "\n", + "\n", + "\n", + "n9->n13\n", + "\n", + "\n", + "29\n", + "\n", + "\n", + "\n", + "n9->n14\n", + "\n", + "\n", + "25\n", + "\n", + "\n", + "\n", + "n9->n15\n", + "\n", + "\n", + "26\n", + "\n", + "\n", + "\n", + "n10->n14\n", + "\n", + "\n", + "30\n", + "\n", + "\n", + "\n", + "n10->n16\n", + "\n", + "\n", + "27\n", + "\n", + "\n", + "\n", + "n11->n15\n", + "\n", + "\n", + "31\n", + "\n", + "\n", + "\n", + "n11->n16\n", + "\n", + "\n", + "28\n", + "\n", + "\n", + "\n", + "n12->n16\n", + "\n", + "\n", + "32\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ], + "cell_type": "code", + "source": [ + "add_loops!(G::LGraph) = begin\n", + " for v in parts(G,:V)\n", + " add_edge!(G, v,v)\n", + " end\n", + " return G\n", + "end\n", + "add_loops(G::LGraph) = add_loops!(copy(G))\n", + "\n", + "Gᵣ = add_loops(G)\n", + "P = apex(product(Gᵣ, G))\n", + "draw(apex(product(Gᵣ, G)))" + ], + "metadata": {}, + "execution_count": 21 + }, + { + "cell_type": "markdown", + "source": [ + "We can look at the shape of commuting triangle, which is our favorite 3-vertex graph." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n1->n1\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2->n2\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 22 + } + ], + "cell_type": "code", + "source": [ + "T = @acset LGraph begin\n", + " V = 3\n", + " E = 3\n", + " L = 3\n", + " src = [1,1,2]\n", + " tgt = [2,3,3]\n", + " label = [1,2,3]\n", + "end\n", + "Tᵣ = add_loops(T)\n", + "draw(Tᵣ)\n", + "\n", + "E = @acset LGraph begin\n", + " V = 2\n", + " E = 1\n", + " L = 2\n", + " src = [1]\n", + " tgt = [2]\n", + " label = [1,2]\n", + "end\n", + "Eᵣ = add_loops(E)\n", + "draw(Eᵣ)" + ], + "metadata": {}, + "execution_count": 22 + }, + { + "cell_type": "markdown", + "source": [ + "We can draw the product of the edge graph and the triangle graph to get the shape of a triangular prism. You can view this product as extruding `Tᵣ` along `Eᵣ`. Catlab provides a `ReflexiveGraph` as a type that handles these self-loops more intelligently than we are here. Graphviz struggles with the layout here because the product graph will include edges that are a step in both directions. This [blog post](https://www.algebraicjulia.org/blog/post/2021/04/cset-graphs-3/) does a good job explaining products in differnt kinds of graph categories." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "6-element Vector{Int64}:\n 1\n 2\n 3\n 1\n 2\n 3" + }, + "metadata": {}, + "execution_count": 23 + } + ], + "cell_type": "code", + "source": [ + "draw(apex(product(Tᵣ,Eᵣ)))\n", + "legs(product(Tᵣ, Eᵣ))[1][:V] |> collect" + ], + "metadata": {}, + "execution_count": 23 + }, + { + "cell_type": "markdown", + "source": [ + "Another limit is the pullback. If you have a cospan, which is a diagram of the shape `X ⟶ A ⟵ Y`, you can pull back one arrow along the other by solving a system of equations." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#3E2A81\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#BB3D3A\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"10\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"11\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"12\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"13\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"14\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n1->n1\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n1->n4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n1->n5\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n2->n2\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n3->n3\n", + "\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n3->n5\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n4->n4\n", + "\n", + "\n", + "13\n", + "\n", + "\n", + "\n", + "n4->n5\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n5->n5\n", + "\n", + "\n", + "14\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 24 + } + ], + "cell_type": "code", + "source": [ + "PB₂₂ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[2]);\n", + "draw(apex(PB₂₂))" + ], + "metadata": {}, + "execution_count": 24 + }, + { + "cell_type": "markdown", + "source": [ + "Note that the pullback depends not only on X,A,Y but also on the two arrows. You can play around with the choice of morphisms to gain an intuition of how the pullback depends on the morphisms." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#532D75\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A73A46\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"10\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n1->n1\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n1->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n2\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n3->n3\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n4->n4\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 25 + } + ], + "cell_type": "code", + "source": [ + "PB₂₃ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[3]);\n", + "draw(apex(PB₂₃))" + ], + "metadata": {}, + "execution_count": 25 + }, + { + "cell_type": "markdown", + "source": [ + "By constructions, the pullback is always a subobject (monic homomorphism) into the product. Catlab can enumerate all such monoic homs." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "34" + }, + "metadata": {}, + "execution_count": 26 + } + ], + "cell_type": "code", + "source": [ + "homomorphisms(apex(PB₂₂), apex(product(Tᵣ,Tᵣ)), monic=true) |> length" + ], + "metadata": {}, + "execution_count": 26 + }, + { + "cell_type": "markdown", + "source": [ + "## Colimits and Composition by Glueing\n", + "The dual concept to limits is colimits and if limits have vibes of taking all pairs that satisfy certain constraints, colimits have the vibes of designers just gluing stuff together to make it work." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "In order to illustrate this we will be gluing triangles together to make a mesh. We start by defining the point `X`, which is the shape of the boundary along which we will glue and the morphism `ℓ₁`, which is the place in `T` that we consider as the boundary." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 27 + } + ], + "cell_type": "code", + "source": [ + "X = @acset LGraph begin\n", + " E = 0\n", + " V = 1\n", + " L = 3\n", + " label=[2]\n", + "end\n", + "ℓ₁ = ACSetTransformation(X,T, V=[2],L=1:3)\n", + "draw(X)" + ], + "metadata": {}, + "execution_count": 27 + }, + { + "cell_type": "markdown", + "source": [ + "We have to check that the morphism is valid before we go and compute out pushout." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n2\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 28 + } + ], + "cell_type": "code", + "source": [ + "is_natural(ℓ₁)\n", + "P = pushout(ℓ₁, ℓ₁)\n", + "draw(apex(P))" + ], + "metadata": {}, + "execution_count": 28 + }, + { + "cell_type": "markdown", + "source": [ + "Now we want to repeat the gluing process to get a bigger mesh. So we are going to need a bigger interface." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"2\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 29 + } + ], + "cell_type": "code", + "source": [ + "I = @acset LGraph begin\n", + " V = 2\n", + " L = 3\n", + " label = [1,1]\n", + "end\n", + "draw(I)" + ], + "metadata": {}, + "execution_count": 29 + }, + { + "cell_type": "markdown", + "source": [ + "We have to specify how this interface embeds into both of the things we want to glue. In this case we are gluing a copy of `P` onto itself." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"6\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"7\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"10\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"11\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"12\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n3->n6\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n3->n7\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n2\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n5->n8\n", + "\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n6->n7\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n6->n8\n", + "\n", + "\n", + "12\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 30 + } + ], + "cell_type": "code", + "source": [ + "ll = ACSetTransformation(I, apex(P), V=[3,5], L =[3,1,2])\n", + "is_natural(ll)\n", + "lr = ACSetTransformation(I, apex(P), V=[1,4], L =[1,3,2])\n", + "is_natural(lr)\n", + "P₂ = pushout(ll, lr);\n", + "draw(apex(P₂))" + ], + "metadata": {}, + "execution_count": 30 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphs/graphs_label/8d1b2d17.svg b/v0.16.12/generated/graphs/graphs_label/8d1b2d17.svg new file mode 100644 index 000000000..bef574e91 --- /dev/null +++ b/v0.16.12/generated/graphs/graphs_label/8d1b2d17.svg @@ -0,0 +1,333 @@ + + + + + + +G + + + +n1 + +1 + + + +n5 + +5 + + + +n1->n5 + + +5 + + + +n6 + +6 + + + +n1->n6 + + +1 + + + +n7 + +7 + + + +n1->n7 + + +2 + + + +n9 + +9 + + + +n1->n9 + + +13 + + + +n10 + +10 + + + +n1->n10 + + +9 + + + +n11 + +11 + + + +n1->n11 + + +10 + + + +n2 + +2 + + + +n2->n6 + + +6 + + + +n8 + +8 + + + +n2->n8 + + +3 + + + +n2->n10 + + +14 + + + +n12 + +12 + + + +n2->n12 + + +11 + + + +n3 + +3 + + + +n3->n7 + + +7 + + + +n3->n8 + + +4 + + + +n3->n11 + + +15 + + + +n3->n12 + + +12 + + + +n4 + +4 + + + +n4->n8 + + +8 + + + +n4->n12 + + +16 + + + +n13 + +13 + + + +n5->n13 + + +21 + + + +n14 + +14 + + + +n5->n14 + + +17 + + + +n15 + +15 + + + +n5->n15 + + +18 + + + +n6->n14 + + +22 + + + +n16 + +16 + + + +n6->n16 + + +19 + + + +n7->n15 + + +23 + + + +n7->n16 + + +20 + + + +n8->n16 + + +24 + + + +n9->n13 + + +29 + + + +n9->n14 + + +25 + + + +n9->n15 + + +26 + + + +n10->n14 + + +30 + + + +n10->n16 + + +27 + + + +n11->n15 + + +31 + + + +n11->n16 + + +28 + + + +n12->n16 + + +32 + + + diff --git a/v0.16.12/generated/graphs/graphs_label/b7f22113.svg b/v0.16.12/generated/graphs/graphs_label/b7f22113.svg new file mode 100644 index 000000000..40b65ba96 --- /dev/null +++ b/v0.16.12/generated/graphs/graphs_label/b7f22113.svg @@ -0,0 +1,221 @@ + + + + + + +G + + + +n1 + +1 + + + +n6 + +6 + + + +n1->n6 + + +1 + + + +n7 + +7 + + + +n1->n7 + + +2 + + + +n10 + +10 + + + +n1->n10 + + +5 + + + +n11 + +11 + + + +n1->n11 + + +6 + + + +n2 + +2 + + + +n8 + +8 + + + +n2->n8 + + +3 + + + +n12 + +12 + + + +n2->n12 + + +7 + + + +n3 + +3 + + + +n3->n8 + + +4 + + + +n3->n12 + + +8 + + + +n4 + +4 + + + +n5 + +5 + + + +n14 + +14 + + + +n5->n14 + + +9 + + + +n15 + +15 + + + +n5->n15 + + +10 + + + +n16 + +16 + + + +n6->n16 + + +11 + + + +n7->n16 + + +12 + + + +n9 + +9 + + + +n9->n14 + + +13 + + + +n9->n15 + + +14 + + + +n10->n16 + + +15 + + + +n11->n16 + + +16 + + + +n13 + +13 + + + diff --git a/v0.16.12/generated/graphs/graphs_label/index.html b/v0.16.12/generated/graphs/graphs_label/index.html new file mode 100644 index 000000000..59c30cd12 --- /dev/null +++ b/v0.16.12/generated/graphs/graphs_label/index.html @@ -0,0 +1,1142 @@ + +Labeled Graphs · Catlab.jl

Labeled Graphs

This example demonstrates how to define new C-Sets from existing C-Sets via the example of adding labels to a graph. We treat labels as members of an arbitrary FinSet of labels rather than a data attribute for pedagogical reasons. When you think of graphs where the labels are numbers, colors, or values of some kind, you would want to make them attributes. The motivation for this example is to be the simplest extension to the theory of graphs that you could possibly make.

using Catlab.Theories, Catlab.CategoricalAlgebra
+using Catlab.Graphs, Catlab.Graphics
+
+using Colors
+draw(g) = to_graphviz(g, node_labels=true, edge_labels=true)
draw (generic function with 1 method)

We start with the theory of graphs, which is copied from Catlab.Graphs.BasicGraphs. The two objects are the edges and vertices and we have two functions src,tgt that assign to every edge the source vertex and target vertex respectively. Functors from this category to Set (diagrams in Set of this shape) are category theoretic graphs (directed multigraphs).

@present SchGraph(FreeSchema) begin
+  V::Ob
+  E::Ob
+  src::Hom(E,V)
+  tgt::Hom(E,V)
+end
+
+to_graphviz(SchGraph)

To the theory of graphs we want to add a set of labels L and map that assigns to every vertex to its label in L.

@present SchLGraph <: SchGraph begin
+  L::Ob
+  label::Hom(V,L)
+end
+
+to_graphviz(SchLGraph)

Catlab will automatically generate all the data structure and algorithms (storing, mutating, serializing, etc.) our LGraphs for us. This snippet declares that the Julia type LGraph should be composed of objects of the functor category SchLGraph → Skel(FinSet), where Skel(FinSet) is the subcategory of Set containing finite sets of form 1:n. We want our Julia type LGraph to inherit from the type AbstractGraph so that we can run graph algorithms on it. And we want the generated data structures to make an index of the maps src, tgt, and label so that looking up the in and outneighbors of vertex is fast and accessing all vertices by label is also fast.

Note: This schema differs from that of LabeledGraph in Catlab.Graphs by making the label type an object (Ob) rather than attribute type (AttrType). In this case, the set of labels can vary from instance to instance and homomorphisms can rename labels; in the other case, the set of labels is fixed by a Julia type, such as Int or Symbol, and label values must be strictly preserved homomorphisms. The graph theory literature does not always distinguish very carefully between these two cases.

@acset_type LGraph(SchLGraph, index=[:src,:tgt,:label]) <: AbstractGraph
Main.LGraph

We need to tell Catlab how to convert our LGraph type into the normal Graph type by taking just the edges and vertices. This could be computed with Functorial Data Migration, but that is left for another sketch.

to_graph(g::LGraph) = begin
+  h = Graph(nparts(g,:V))
+  for e in edges(g)
+    add_edge!(h, g[e, :src], g[e,:tgt])
+  end
+  return h
+end
to_graph (generic function with 1 method)

Graphviz doesn't automatically know how we want to draw the labels, so we have to explicitly provide code that converts them to colors on the vertices. Note that we aren't calling these colored graphs, because that would imply some connectivity constraints on which vertices are allowed to be colored with the same colors. These labels are arbitrary, but we use color to visually encode them.

GraphvizGraphs.to_graphviz(g::LGraph; kw...) =
+  to_graphviz(to_graphviz_property_graph(g; kw...))
+
+function GraphvizGraphs.to_graphviz_property_graph(g::LGraph; kw...)
+  h = to_graph(g)
+  pg = to_graphviz_property_graph(h; kw...)
+  vcolors = hex.(range(colorant"#0021A5", stop=colorant"#FA4616", length=nparts(g, :L)))
+  for v in vertices(g)
+    l = g[v, :label]
+    set_vprops!(pg, v, Dict(:color => "#$(vcolors[l])"))
+  end
+  pg
+end
+
+draw(G::LGraph) = to_graphviz(G, node_labels=true, edge_labels=true)
draw (generic function with 2 methods)

Now we can start making some LGraph instances.

G = @acset LGraph begin
+  V = 4
+  E = 4
+  L = 4
+  src = [1,1,2,3]
+  tgt = [2,3,4,4]
+  label = [1,2,3,4]
+end
+
+draw(G)

The graph G has a 1-1 map between vertices and labels. That isn't necessary.

H = @acset LGraph begin
+  V = 4
+  E = 4
+  L = 3
+  src = [1,1,2,3]
+  tgt = [2,3,4,4]
+  label = [1,2,2,3]
+end
+
+draw(H)

We can look at some homomorphisms from G to H by their action on the labels or on the vertices.

homsᵥ(G,H) = map(α -> α[:V], homomorphisms(G, H))
+homsₗ(G,H) = map(α -> α[:L], homomorphisms(G, H))
homsₗ (generic function with 1 method)

αₗ: G→ H

homsₗ(G,H)
4-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 3], 4, 3)
+ FinFunction([1, 2, 2, 3], 4, 3)
+ FinFunction([1, 2, 2, 3], 4, 3)
+ FinFunction([1, 2, 2, 3], 4, 3)

αᵥ: G→ H

homsᵥ(G,H)
4-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4], 4, 4)
+ FinFunction([1, 2, 3, 4], 4, 4)
+ FinFunction([1, 3, 2, 4], 4, 4)
+ FinFunction([1, 3, 3, 4], 4, 4)

Note that if we reverse the direction of our homomorphism search, we get fewer matches even though the two LGraphs are isomorphic as graphs. The fact that in H vertex two and three are the same label means we have to send them to the same vertex in G.

homsᵥ(H,G)
2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4], 4, 4)
+ FinFunction([1, 3, 3, 4], 4, 4)

We can build some bigger examples like A.

A = @acset LGraph begin
+  V = 6
+  E = 7
+  L = 3
+  src = [1,1,2,3,2,5,4]
+  tgt = [2,3,4,4,5,6,6]
+  label = [1,2,2,3,2,3]
+end
+draw(A)

and B.

B = @acset LGraph begin
+  V = 6
+  E = 7
+  L = 4
+  src = [1,1,2,3,2,5,4]
+  tgt = [2,3,4,4,5,6,6]
+  label = [1,2,4,3,2,3]
+end
+draw(B)

The morphisms from A to B and B to A are also different, showing how the labels affect the structure in this category.

homsᵥ(A,B)
1-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4, 5, 6], 6, 6)

There are more morphisms from B to A than A to B.

homsᵥ(B,A)
2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4, 5, 6], 6, 6)
+ FinFunction([1, 2, 3, 4, 5, 6], 6, 6)

There are two automorphisms on A

homsᵥ(A,A)
2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4, 5, 6], 6, 6)
+ FinFunction([1, 2, 3, 4, 5, 6], 6, 6)

And two automorphisms on B

homsᵥ(B,B)
2-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4, 5, 6], 6, 6)
+ FinFunction([1, 2, 3, 4, 5, 6], 6, 6)

But if we forget about the labels and look at the automorphisms of the underlying graph, we get more automorphisms!

A₀ = to_graph(A)
+homsᵥ(A₀, A₀)
8-element Vector{Catlab.CategoricalAlgebra.FinSets.FinDomFunctionVector{Int64, Vector{Int64}, Catlab.CategoricalAlgebra.FinSets.FinSetInt}}:
+ FinFunction([1, 2, 2, 4, 4, 6], 6, 6)
+ FinFunction([1, 2, 2, 4, 5, 6], 6, 6)
+ FinFunction([1, 2, 2, 5, 4, 6], 6, 6)
+ FinFunction([1, 2, 2, 5, 5, 6], 6, 6)
+ FinFunction([1, 2, 3, 4, 4, 6], 6, 6)
+ FinFunction([1, 2, 3, 4, 5, 6], 6, 6)
+ FinFunction([1, 3, 2, 4, 4, 6], 6, 6)
+ FinFunction([1, 3, 3, 4, 4, 6], 6, 6)

Limits and Composition by Multiplication

Catlab has an implementation of limits for any C-Sets over any schema. So, we can just ask about labeled graphs. Notice that we get more distinct colors in the product than in either initial graph. This is because the labels of the product are pairs of labels from the factors. If G has n colors and H has m colors G×H will have n×m colors.

draw(apex(product(G,G)))
Example block output

The graph above looks weirdly disconnected and probably wasn't what you expected to see as the product. When we compose with products, we often want to add the reflexive edges in order to get the expected notion of product.

add_loops!(G::LGraph) = begin
+  for v in parts(G,:V)
+    add_edge!(G, v,v)
+  end
+  return G
+end
+add_loops(G::LGraph) = add_loops!(copy(G))
+
+Gᵣ = add_loops(G)
+P = apex(product(Gᵣ, G))
+draw(apex(product(Gᵣ, G)))
Example block output

We can look at the shape of commuting triangle, which is our favorite 3-vertex graph.

T = @acset LGraph begin
+  V = 3
+  E = 3
+  L = 3
+  src = [1,1,2]
+  tgt = [2,3,3]
+  label = [1,2,3]
+end
+Tᵣ = add_loops(T)
+draw(Tᵣ)
+
+E = @acset LGraph begin
+  V = 2
+  E = 1
+  L = 2
+  src = [1]
+  tgt = [2]
+  label = [1,2]
+end
+Eᵣ = add_loops(E)
+draw(Eᵣ)

We can draw the product of the edge graph and the triangle graph to get the shape of a triangular prism. You can view this product as extruding Tᵣ along Eᵣ. Catlab provides a ReflexiveGraph as a type that handles these self-loops more intelligently than we are here. Graphviz struggles with the layout here because the product graph will include edges that are a step in both directions. This blog post does a good job explaining products in differnt kinds of graph categories.

draw(apex(product(Tᵣ,Eᵣ)))
+legs(product(Tᵣ, Eᵣ))[1][:V] |> collect
6-element Vector{Int64}:
+ 1
+ 2
+ 3
+ 1
+ 2
+ 3

Another limit is the pullback. If you have a cospan, which is a diagram of the shape X ⟶ A ⟵ Y, you can pull back one arrow along the other by solving a system of equations.

PB₂₂ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[2]);
+draw(apex(PB₂₂))

Note that the pullback depends not only on X,A,Y but also on the two arrows. You can play around with the choice of morphisms to gain an intuition of how the pullback depends on the morphisms.

PB₂₃ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[3]);
+draw(apex(PB₂₃))

By constructions, the pullback is always a subobject (monic homomorphism) into the product. Catlab can enumerate all such monoic homs.

homomorphisms(apex(PB₂₂), apex(product(Tᵣ,Tᵣ)), monic=true) |> length
34

Colimits and Composition by Glueing

The dual concept to limits is colimits and if limits have vibes of taking all pairs that satisfy certain constraints, colimits have the vibes of designers just gluing stuff together to make it work.

In order to illustrate this we will be gluing triangles together to make a mesh. We start by defining the point X, which is the shape of the boundary along which we will glue and the morphism ℓ₁, which is the place in T that we consider as the boundary.

X = @acset LGraph begin
+  E = 0
+  V = 1
+  L = 3
+  label=[2]
+end
+ℓ₁ = ACSetTransformation(X,T, V=[2],L=1:3)
+draw(X)

We have to check that the morphism is valid before we go and compute out pushout.

is_natural(ℓ₁)
+P = pushout(ℓ₁, ℓ₁)
+draw(apex(P))

Now we want to repeat the gluing process to get a bigger mesh. So we are going to need a bigger interface.

I = @acset LGraph begin
+  V = 2
+  L = 3
+  label = [1,1]
+end
+draw(I)

We have to specify how this interface embeds into both of the things we want to glue. In this case we are gluing a copy of P onto itself.

ll = ACSetTransformation(I, apex(P), V=[3,5], L =[3,1,2])
+is_natural(ll)
+lr = ACSetTransformation(I, apex(P), V=[1,4], L =[1,3,2])
+is_natural(lr)
+P₂ = pushout(ll, lr);
+draw(apex(P₂))
diff --git a/v0.16.12/generated/graphs/subgraphs.ipynb b/v0.16.12/generated/graphs/subgraphs.ipynb new file mode 100644 index 000000000..bece0bad0 --- /dev/null +++ b/v0.16.12/generated/graphs/subgraphs.ipynb @@ -0,0 +1,1556 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Algebra of subgraphs" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Catlab.Graphs, Catlab.Graphics\n", + "using Catlab.Theories, Catlab.CategoricalAlgebra" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "A *subgraph* of a graph $G$ is a monomorphism $A \\rightarrowtail G$. Because\n", + "the category of graphs is a presheaf topos, its subobjects have a rich\n", + "algebraic structure, which we will explore in this vignette.\n", + "\n", + "Throughout the vignette, we will work with subgraphs of the following graph." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"7\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "G = cycle_graph(Graph, 4) ⊕ path_graph(Graph, 2) ⊕ cycle_graph(Graph, 1)\n", + "add_edge!(G, 3, add_vertex!(G))\n", + "\n", + "to_graphviz(G, node_labels=true, edge_labels=true)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "## Meet and join\n", + "\n", + "The basic operations of [meet](https://ncatlab.org/nlab/show/meet) or\n", + "intersection ($\\wedge$), [join](https://ncatlab.org/nlab/show/join) or union\n", + "($\\vee$), [top](https://ncatlab.org/nlab/show/top) or maximum ($\\top$),\n", + "[bottom](https://ncatlab.org/nlab/show/bottom) or minimum ($\\bot$) are all\n", + "computed pointwise: separately on vertices and edges.\n", + "\n", + "Consider the following two subgraphs." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "(A = Subobject(G, V=1:4, E=[1,2,4])) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "(B = Subobject(G, V=[2,3,4,7,8], E=[2,3,6,7])) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "The *join* is defined as left adjoint to the diagonal, making it the *least\n", + "upper bound*:\n", + "\n", + "$$A \\vee B \\leq C \\qquad\\text{iff}\\qquad A \\leq C \\text{ and } B \\leq C.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "A ∨ B |> to_graphviz" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Dually, the *meet* is defined as right adjoint to the diagonal, making it the\n", + "*greatest lower bound*:\n", + "\n", + "$$C \\leq A \\text{ and } C \\leq B \\qquad\\text{iff}\\qquad C \\leq A \\wedge B.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "A ∧ B |> to_graphviz" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "## Implication and negation\n", + "\n", + "The other operations, beginning with implication ($\\Rightarrow$) and negation\n", + "($\\neg$) are more interesting because they do not have pointwise formulas.\n", + "\n", + "*Implication* is defined as the right adjoint to the meet:\n", + "\n", + "$$C \\wedge A \\leq B \\qquad\\text{iff}\\qquad C \\leq A \\Rightarrow B.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "(A ⟹ B) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "*Negation* is defined by setting $B = \\bot$ in the above formula:\n", + "\n", + "$$C \\wedge A = \\bot \\qquad\\text{iff}\\qquad C \\leq \\neg A.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "¬A |> to_graphviz" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "### Induced subgraph as a double negation\n", + "\n", + "The logic of subgraphs, and of subobjects in presheaf toposes generally, is\n", + "not classical. Specifically, subobjects form a [Heyting\n", + "algebra](https://ncatlab.org/nlab/show/Heyting+algebra) but not a [Boolean\n", + "algebra](https://ncatlab.org/nlab/show/Boolean+algebra). This means that the\n", + "law of excluded middle does not hold: in general, $\\neg \\neg A \\neq A$.\n", + "\n", + "Applying the double negation to a discrete subgraph gives the subgraph induced\n", + "by those vertices." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "(C = Subobject(G, V=1:4)) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "¬(¬C) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "## Subtraction and non\n", + "\n", + "The subojects also form [co-Heyting\n", + "algebra](https://ncatlab.org/nlab/show/co-Heyting+algebra) and hence a\n", + "bi-Heyting algebra.\n", + "\n", + "*Subtraction* is defined dually to implication as the left adjoint to the\n", + "join:\n", + "\n", + "$$A \\leq B \\vee C \\qquad\\text{iff}\\qquad A \\setminus B \\leq C.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "(A \\ B) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "*Non* is defined by setting $A = \\top$ in the above formula:\n", + "\n", + "$$\\top = B \\vee C \\qquad\\text{iff}\\qquad {\\sim} B \\leq C.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "~A |> to_graphviz" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "### Boundary via non\n", + "\n", + "A [*boundary*](https://ncatlab.org/nlab/show/co-Heyting+boundary) operator can\n", + "be defined using the non operator:\n", + "\n", + "$$\\partial A := A \\wedge {\\sim} A.$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"cornflowerblue\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"point\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "n5->n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "n7->n7\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "(A ∧ ~A) |> to_graphviz" + ], + "metadata": {}, + "execution_count": 13 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/graphs/subgraphs/index.html b/v0.16.12/generated/graphs/subgraphs/index.html new file mode 100644 index 000000000..a584717c2 --- /dev/null +++ b/v0.16.12/generated/graphs/subgraphs/index.html @@ -0,0 +1,1161 @@ + +Algebra of subgraphs · Catlab.jl

Algebra of subgraphs

using Catlab.Graphs, Catlab.Graphics
+using Catlab.Theories, Catlab.CategoricalAlgebra

A subgraph of a graph $G$ is a monomorphism $A \rightarrowtail G$. Because the category of graphs is a presheaf topos, its subobjects have a rich algebraic structure, which we will explore in this vignette.

Throughout the vignette, we will work with subgraphs of the following graph.

G = cycle_graph(Graph, 4) ⊕ path_graph(Graph, 2) ⊕ cycle_graph(Graph, 1)
+add_edge!(G, 3, add_vertex!(G))
+
+to_graphviz(G, node_labels=true, edge_labels=true)

Meet and join

The basic operations of meet or intersection ($\wedge$), join or union ($\vee$), top or maximum ($\top$), bottom or minimum ($\bot$) are all computed pointwise: separately on vertices and edges.

Consider the following two subgraphs.

(A = Subobject(G, V=1:4, E=[1,2,4])) |> to_graphviz
(B = Subobject(G, V=[2,3,4,7,8], E=[2,3,6,7])) |> to_graphviz

The join is defined as left adjoint to the diagonal, making it the least upper bound:

\[A \vee B \leq C \qquad\text{iff}\qquad A \leq C \text{ and } B \leq C.\]

A ∨ B |> to_graphviz

Dually, the meet is defined as right adjoint to the diagonal, making it the greatest lower bound:

\[C \leq A \text{ and } C \leq B \qquad\text{iff}\qquad C \leq A \wedge B.\]

A ∧ B |> to_graphviz

Implication and negation

The other operations, beginning with implication ($\Rightarrow$) and negation ($\neg$) are more interesting because they do not have pointwise formulas.

Implication is defined as the right adjoint to the meet:

\[C \wedge A \leq B \qquad\text{iff}\qquad C \leq A \Rightarrow B.\]

(A ⟹ B) |> to_graphviz

Negation is defined by setting $B = \bot$ in the above formula:

\[C \wedge A = \bot \qquad\text{iff}\qquad C \leq \neg A.\]

¬A |> to_graphviz

Induced subgraph as a double negation

The logic of subgraphs, and of subobjects in presheaf toposes generally, is not classical. Specifically, subobjects form a Heyting algebra but not a Boolean algebra. This means that the law of excluded middle does not hold: in general, $\neg \neg A \neq A$.

Applying the double negation to a discrete subgraph gives the subgraph induced by those vertices.

(C = Subobject(G, V=1:4)) |> to_graphviz
¬(¬C) |> to_graphviz

Subtraction and non

The subojects also form co-Heyting algebra and hence a bi-Heyting algebra.

Subtraction is defined dually to implication as the left adjoint to the join:

\[A \leq B \vee C \qquad\text{iff}\qquad A \setminus B \leq C.\]

(A \ B) |> to_graphviz

Non is defined by setting $A = \top$ in the above formula:

\[\top = B \vee C \qquad\text{iff}\qquad {\sim} B \leq C.\]

~A |> to_graphviz

Boundary via non

A boundary operator can be defined using the non operator:

\[\partial A := A \wedge {\sim} A.\]

(A ∧ ~A) |> to_graphviz
diff --git a/v0.16.12/generated/sketches/cat_elements.ipynb b/v0.16.12/generated/sketches/cat_elements.ipynb new file mode 100644 index 000000000..28a73e53b --- /dev/null +++ b/v0.16.12/generated/sketches/cat_elements.ipynb @@ -0,0 +1,1601 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# The Category of Elements\n", + "A very useful construction in applied category theory is the Category of Elements, which is also called the Grothendieck construction. This is a very general technique in category theory, but we will look at how you can use it to explain why graphs are so useful in computer science. We have already seen that C-Sets are a model of relational databases that can be used to store data as a collection of interlocking tables. Relational databases are the bread and butter of the computing industry. Every company on earth uses software that is backed by a relational database. Most data that is not stored in a relational DB is often stored in some kind of graph data structure. This sketch will show how these approaches are interchangeable via the category of elements, which associates to every database instance a graph and a graph homomorphism into the schema of the graph." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using GATlab, Catlab.CategoricalAlgebra, Catlab.Graphs, Catlab.Graphics\n", + "using Colors" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "Let's tell Catlab how to draw categories of elements." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "draw (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "function graph(el::Elements)\n", + " F = FinFunctor(Dict(:V => :El, :E => :Arr), Dict(:src => :src, :tgt => :tgt),\n", + " SchGraph, SchElements)\n", + " ΔF = DataMigrationFunctor(F, Elements{Symbol}, Graph)\n", + " return ΔF(el)\n", + "end\n", + "\n", + "safecolors(start, stop, len) = if len > 1\n", + " return hex.(range(start, stop=stop, length=len))\n", + "else\n", + " return [hex.(start)]\n", + "end\n", + "\n", + "function draw(f::Elements; kw...)\n", + " pg = to_graphviz_property_graph(graph(f);\n", + " node_labels=true, edge_labels=true, prog=\"neato\", kw...)\n", + " vcolors = safecolors(colorant\"#0021A5\", colorant\"#FA4616\", nparts(f, :Ob))\n", + " ecolors = safecolors(colorant\"#6C9AC3\", colorant\"#E28F41\", nparts(f, :Hom))\n", + " for v in parts(f, :El)\n", + " fv = f[v, :πₑ]\n", + " set_vprops!(pg, v, Dict(:color => \"#$(vcolors[fv])\", :label=>\"$v:$(f[v,[:πₑ, :nameo]])\"))\n", + " end\n", + " for e in parts(f, :Arr)\n", + " fe = f[e, :πₐ]\n", + " set_eprops!(pg, e, Dict(:color => \"#$(ecolors[fe])\"))\n", + " end\n", + " to_graphviz(pg)\n", + "end\n", + "\n", + "draw(g) = to_graphviz(g, node_labels=true, edge_labels=true, prog=\"neato\")" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "## The simplest schema\n", + "First we will look at discrete dynamical systems. The set S is our state space and the funct nxt associates to every state, the next state in the system. This is a deterministic dynamical system with finitely many states and discrete time." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Main.var\"##242\".DDS {S:3}\n┌───┬─────┐\n│\u001b[1m S │\u001b[1m nxt │\n├───┼─────┤\n│\u001b[1m 1 │ 2 │\n│\u001b[1m 2 │ 3 │\n│\u001b[1m 3 │ 1 │\n└───┴─────┘\n", + "text/html": [ + "
\n", + "Main.var\"##242\".DDS {S:3}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Snxt
12
23
31
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "@present SchDDS(FreeSchema) begin\n", + " S::Ob\n", + " nxt::Hom(S, S)\n", + "end\n", + "\n", + "@acset_type DDS(SchDDS, index=[:nxt])\n", + "\n", + "fₓ = @acset DDS begin\n", + " S = 3\n", + " nxt = [2,3,1]\n", + "end" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Now if you want to draw a DDS, you might think to draw each state as a vertex and the next relationship as an arrow from one state to the next state. If your intuition selected that representation, you have already discovered a special case of the category of elements" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "elᶠ = elements(fₓ)\n", + "draw(graph(elᶠ))" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "As you are quite far in your category theoretic training, you are surely suspicious of the idea that you would construct the category of elements of a DDS and get a graph. We have a categorical construction, so your intuition should be saying \"there should be some kind of morphism that goes with this object\". And there is, the Elements of a C-Set X is a graph whose vertices are rows in the tables of X and whose edges are the foreign key relationships in X, along with a graph homomorphism into the schema C. We can draw this using the same color coding convention we used to draw graph homomorphisms." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1:S\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"2:S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"3:S\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1:S\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2:S\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3:S\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "draw(elᶠ)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "We can scale up our DDS drawing too." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1:S\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"2:S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"3:S\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"4:S\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"5:S\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"6:S\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"7:S\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"7\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1:S\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2:S\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3:S\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4:S\n", + "\n", + "\n", + "\n", + "n4->n1\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5:S\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7:S\n", + "\n", + "\n", + "\n", + "n5->n7\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6:S\n", + "\n", + "\n", + "\n", + "n6->n7\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n7->n4\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "Fₓ = @acset DDS begin\n", + " S = 7\n", + " nxt = [2,3,1, 1,7,7,4]\n", + "end\n", + "draw(elements(Fₓ))" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "A category of elements derived from a C-Set is stored as a C-Set of on a different schema. You can see that it is the data of a graph homomorphism where the codomain graph has vertex and edge labels. The two projections πₑ and πₐ are the components of a natural transformation between graphs viewed as functors into Set. The names are attributes usually of type Symbol." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"El\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Arr\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Ob\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Hom\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"point\", :xlabel => \"Name\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"dom\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"cod\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"πₑ\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"πₐ\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"nameo\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"nameh\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "El\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "Ob\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "πₑ\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "Arr\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "Hom\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "πₐ\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "Name\n", + "\n", + "\n", + "\n", + "n3->n5\n", + "\n", + "\n", + "nameo\n", + "\n", + "\n", + "\n", + "n4->n3\n", + "\n", + "\n", + "dom\n", + "\n", + "\n", + "\n", + "n4->n3\n", + "\n", + "\n", + "cod\n", + "\n", + "\n", + "\n", + "n4->n5\n", + "\n", + "\n", + "nameh\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(SchElements)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "In the case of a DDS, we have only one object and one morphism in the schema. Since the graph with one edge and one vertices is terminal in *Graph*, there is only one vertex and edge color being used." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## The Elements of a Graph are its Vertices and Edges\n", + "In what might appear as primordial ooze, we can examine the category of elements of a graph. We will look at the commuting triangle graph. Notice how there are 3 vertices and three edges with each edge incident to 2 vertices." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"3\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n2->n3\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "g = @acset Graph begin\n", + " V = 3\n", + " E = 3\n", + " src = [1,2,1]\n", + " tgt = [2,3,3]\n", + "end\n", + "draw(g)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "The category of elements has 6 vertices and 6 edges. The 6 vertices come from 3 vertices of type V and 3 vertices of type E. The 6 edges in this graph are 3 src relationships and 3 target relationships." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1:V\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"2:V\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"3:V\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"4:V\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"5:V\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"6:V\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"7:E\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"8:E\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"9:E\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"10:E\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n12\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n13\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"10\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"11\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"12\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n12\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"13\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n13\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"14\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1:V\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2:V\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3:V\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4:V\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5:V\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6:V\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7:E\n", + "\n", + "\n", + "\n", + "n7->n1\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n7->n2\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8:E\n", + "\n", + "\n", + "\n", + "n8->n2\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n8->n3\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "9:E\n", + "\n", + "\n", + "\n", + "n9->n1\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n9->n3\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "10:E\n", + "\n", + "\n", + "\n", + "n10->n3\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n10->n5\n", + "\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n11\n", + "\n", + "11:E\n", + "\n", + "\n", + "\n", + "n11->n5\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n11->n6\n", + "\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n12\n", + "\n", + "12:E\n", + "\n", + "\n", + "\n", + "n12->n3\n", + "\n", + "\n", + "13\n", + "\n", + "\n", + "\n", + "n12->n6\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n13\n", + "\n", + "13:E\n", + "\n", + "\n", + "\n", + "n13->n4\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n13->n4\n", + "\n", + "\n", + "14\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "elᵍ = elements(g)\n", + "draw(elᵍ)\n", + "\n", + "g = @acset Graph begin\n", + " V = 6\n", + " E = 7\n", + " src = [1,2,1,3,5,6,4]\n", + " tgt = [2,3,3,5,6,3,4]\n", + "end\n", + "draw(g)\n", + "draw(elements(g))" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "Notice that the 3 vertices of type E are interspersed between the 3 vertices of type V and vice versa. You can see that the normal visual syntax for a graph is more compact for the special case of graphs. However the category of elements works for any schema C." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Generality of the construction\n", + "Discrete Dynamical Systems and Graphs are clearly data structures from mathematics and so it would make sense that they have a clean representation in the categorical language. But how about a database schema that comes not from mathematics, but from software engineering. We turn to everyone's favorite database example, the HR database at a fictitious company." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Main.var\"##242\".Company" + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "@present SchCompany(FreeSchema) begin\n", + " (P, D, S)::Ob # Person, Department, Salary\n", + " worksin::Hom(P, D) # Every Person works in a Department\n", + " makes::Hom(P, S) # Every Person makes a Salary\n", + " reportsto::Hom(P, P) # Every Person reports to a Person\n", + " managedby::Hom(D, P) # Every Department is managed by a Person\n", + " leq::Hom(S,S) # Salaries are a finite total order\n", + "end\n", + "\n", + "@acset_type Company(SchCompany, index=[])" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "We can draw a company that has 4 people, 2 departments, and 3 distinct salaries." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Main.var\"##242\".Company {P:4, D:2, S:3}\n┌───┬─────────┬───────┬───────────┐\n│\u001b[1m P │\u001b[1m worksin │\u001b[1m makes │\u001b[1m reportsto │\n├───┼─────────┼───────┼───────────┤\n│\u001b[1m 1 │ 1 │ 3 │ 1 │\n│\u001b[1m 2 │ 1 │ 1 │ 1 │\n│\u001b[1m 3 │ 2 │ 2 │ 1 │\n│\u001b[1m 4 │ 2 │ 1 │ 3 │\n└───┴─────────┴───────┴───────────┘\n┌───┬───────────┐\n│\u001b[1m D │\u001b[1m managedby │\n├───┼───────────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 3 │\n└───┴───────────┘\n┌───┬─────┐\n│\u001b[1m S │\u001b[1m leq │\n├───┼─────┤\n│\u001b[1m 1 │ 2 │\n│\u001b[1m 2 │ 3 │\n│\u001b[1m 3 │ 3 │\n└───┴─────┘\n", + "text/html": [ + "
\n", + "Main.var\"##242\".Company {P:4, D:2, S:3}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Pworksinmakesreportsto
1131
2111
3221
4213
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Dmanagedby
11
23
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Sleq
12
23
33
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "cmpy = @acset Company begin\n", + " P = 4\n", + " D = 2\n", + " S = 3\n", + " worksin = [1,1,2,2]\n", + " makes = [3,1,2,1]\n", + " reportsto = [1, 1,1,3]\n", + " managedby = [1,3]\n", + " leq = [2,3,3]\n", + "end" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "A visualization of the elements of this functor is commonly described as a knowledge graph." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1:P\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"2:P\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"3:P\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"4:P\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"5:D\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"6:D\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"7:S\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"8:S\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"9:S\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"1\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#8A97A2\", :label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A79482\", :label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A79482\", :label => \"10\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A79482\", :label => \"11\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#A79482\", :label => \"12\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C49262\", :label => \"13\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#C49262\", :label => \"14\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"15\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"16\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"17\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1:P\n", + "\n", + "\n", + "\n", + "n1->n1\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5:D\n", + "\n", + "\n", + "\n", + "n1->n5\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "9:S\n", + "\n", + "\n", + "\n", + "n1->n9\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2:P\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n", + "n2->n5\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7:S\n", + "\n", + "\n", + "\n", + "n2->n7\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3:P\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6:D\n", + "\n", + "\n", + "\n", + "n3->n6\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8:S\n", + "\n", + "\n", + "\n", + "n3->n8\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4:P\n", + "\n", + "\n", + "\n", + "n4->n3\n", + "\n", + "\n", + "12\n", + "\n", + "\n", + "\n", + "n4->n6\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n4->n7\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n5->n1\n", + "\n", + "\n", + "13\n", + "\n", + "\n", + "\n", + "n6->n3\n", + "\n", + "\n", + "14\n", + "\n", + "\n", + "\n", + "n7->n8\n", + "\n", + "\n", + "15\n", + "\n", + "\n", + "\n", + "n8->n9\n", + "\n", + "\n", + "16\n", + "\n", + "\n", + "\n", + "n9->n9\n", + "\n", + "\n", + "17\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "elᶜ = elements(cmpy)\n", + "draw(elᶜ)" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "The visualization of the category of elements isn't the most compact representation of data, but it is always an option. Once you know how to draw a graph homomorphism as a color-coded graph, you know how to draw any C-Set. The vertices and edges of the domain graph are the rows and fields of the C-Set, and the colors are from the vertices and edges of the schema C, viewed as a graph presenting the category. One thing you lose is the ability to represent path equations in C." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Reconstructing the C-Set from its category of elemnts\n", + "When looking at the graphical representation of the category of elements, you can see that the vertices are numbered sequentially within their vertex type. This order can be computed with the incident function in Catlab. There are inclusions of all the tables in the database instance into the global vertex set of the knowledge graph representation." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3-element Vector{AbstractVector{Int64}}:\n [1, 2, 3, 4]\n [5, 6]\n [7, 8, 9]" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "incident(elᶜ, :, :πₑ)" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "The same goes for the edges (arrows) in the category of elements." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "5-element Vector{AbstractVector{Int64}}:\n [1, 2, 3, 4]\n [5, 6, 7, 8]\n [9, 10, 11, 12]\n [13, 14]\n [15, 16, 17]" + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "incident(elᶜ, :, :πₐ)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "From this information, you can reassemble the knowledge graph into a database. You use the codomain graph as the schema and then these two projections πₑ and πₐ to recover the instance data." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "cset (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "cset(T::Type, el::Elements) = begin\n", + " X = T()\n", + " ℓ = Dict{Int, Int}() # this map reverses the inclusions converting global element numbers into per-table numbers\n", + " for ob in parts(el, :Ob)\n", + " obname = el[ob, :nameo]\n", + " eltsob = incident(el, ob, :πₑ)\n", + " pts = add_parts!(X, obname, length(eltsob))\n", + " map(zip(pts, eltsob)) do (i,x)\n", + " ℓ[x] = i\n", + " end\n", + " end\n", + " for h in parts(el, :Hom)\n", + " nameh = el[h, :nameh]\n", + " arrₕ = incident(el, h, :πₐ)\n", + " doms = map(arrₕ) do e\n", + " ℓ[el[e, :src]]\n", + " end\n", + " codoms = map(arrₕ) do e\n", + " ℓ[el[e, :tgt]]\n", + " end\n", + " set_subpart!(X, doms, nameh, codoms)\n", + " end\n", + " return X\n", + "end" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "We can apply this algorithm to our company knowledge graph to recover our original DB." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "cset(Company, elᶜ)\n", + "cmpy == cset(Company, elᶜ)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "Hopefully you see one reason why graphs are ubiquitous in computer science. Every relational database is isomorphic to a typed graph. You can generate this graph from the database and recover the database from the typed graph. So while knowledge graphs are great for ingesting data when you aren't sure about the structure and useful for some types of computation that involve long paths. You can always build your software on relational databases knowing that you can easily get access to all the graph algorithms by applying the Grothendieck construction." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## The Slice-Elements Transform\n", + "An amazing fact about presheaf toposes is that they are closed under taking slices. In the graphs section of this documentation, you can find a description of bipartite and k-partite graphs as a morphisms into a clique. That definition is very mathematically pleasing because it gives you a category of partitioned graphs that are derived from commuting triangles in Graph. However, for application oriented practitioners, the definition of a bipartite graph as \"a graph with two sets of vertices, where all the edges go between the groups with no edges within either group\" is probably more explicit. For example a classic way to get a bipartite graph would be to look at the graph of authors and papers that those authors wrote. People write papers, people do not write people and papers do not write papers so the authorship graph is bipartite. These two equivalent definitions of a bipartite graph are related via an isomorphism you can find on the [nlab](https://ncatlab.org/nlab/show/category+of+presheaves#RelWithOvercategories). It shows that a slice category of [C,Set]/X is isomorphic to [El(X), Set] which is a cateogory of presheaves on a different schema. Catlab knows how to use this idea to turn a category of elements into a schema for a new category of presheaves. The two directions of the isomorphism are not yet implemented." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"1:V_1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"2:V_1\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#0021A5\", :label => \"3:V_1\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"4:V_2\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#7D345E\", :label => \"5:V_2\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"6:E_1\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"7:E_1\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"8:E_1\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"9:E_1\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#FA4616\", :label => \"10:E_1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#6C9AC3\", :label => \"5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"6\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"7\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"8\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"9\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"#E28F41\", :label => \"10\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0.05\", :margin => \"0\", :shape => \"circle\", :width => \"0.05\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "1:V_1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "2:V_1\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "3:V_1\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "4:V_2\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "5:V_2\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "6:E_1\n", + "\n", + "\n", + "\n", + "n6->n1\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "n6->n4\n", + "\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "7:E_1\n", + "\n", + "\n", + "\n", + "n7->n2\n", + "\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "n7->n5\n", + "\n", + "\n", + "7\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "8:E_1\n", + "\n", + "\n", + "\n", + "n8->n3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "n8->n5\n", + "\n", + "\n", + "8\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "9:E_1\n", + "\n", + "\n", + "\n", + "n9->n3\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "\n", + "n9->n4\n", + "\n", + "\n", + "9\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "10:E_1\n", + "\n", + "\n", + "\n", + "n10->n2\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "n10->n4\n", + "\n", + "\n", + "10\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "e = @acset Graph begin\n", + " V = 2\n", + " E = 1\n", + " src = 1\n", + " tgt = 2\n", + "end\n", + "\n", + "draw(elements(e))\n", + "\n", + "SchBipartite = CatElements.presentation(elements(e))[1]\n", + "to_graphviz(SchBipartite)\n", + "\n", + "@acset_type BipartiteGraph(SchBipartite)\n", + "b = @acset BipartiteGraph begin\n", + " V_1 = 3\n", + " V_2 = 2\n", + " E_1 = 5\n", + " src_E_1 = [1,2,3,3,2]\n", + " tgt_E_1 = [1,2,2,1,1]\n", + "end\n", + "draw(elements(b))" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "As a very advanced exercise, you could try to implement one or both directions of the isomorphism above." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/sketches/cat_elements/373afc21.svg b/v0.16.12/generated/sketches/cat_elements/373afc21.svg new file mode 100644 index 000000000..6122e384f --- /dev/null +++ b/v0.16.12/generated/sketches/cat_elements/373afc21.svg @@ -0,0 +1,189 @@ + + + + + + +G + + + +n1 + +1:V + + + +n2 + +2:V + + + +n3 + +3:V + + + +n4 + +4:V + + + +n5 + +5:V + + + +n6 + +6:V + + + +n7 + +7:E + + + +n7->n1 + + +1 + + + +n7->n2 + + +8 + + + +n8 + +8:E + + + +n8->n2 + + +2 + + + +n8->n3 + + +9 + + + +n9 + +9:E + + + +n9->n1 + + +3 + + + +n9->n3 + + +10 + + + +n10 + +10:E + + + +n10->n3 + + +4 + + + +n10->n5 + + +11 + + + +n11 + +11:E + + + +n11->n5 + + +5 + + + +n11->n6 + + +12 + + + +n12 + +12:E + + + +n12->n3 + + +13 + + + +n12->n6 + + +6 + + + +n13 + +13:E + + + +n13->n4 + + +7 + + + +n13->n4 + + +14 + + + diff --git a/v0.16.12/generated/sketches/cat_elements/46537d0c.svg b/v0.16.12/generated/sketches/cat_elements/46537d0c.svg new file mode 100644 index 000000000..f13dab7db --- /dev/null +++ b/v0.16.12/generated/sketches/cat_elements/46537d0c.svg @@ -0,0 +1,186 @@ + + + + + + +G + + + +n1 + +1:P + + + +n1->n1 + + +9 + + + +n5 + +5:D + + + +n1->n5 + + +1 + + + +n9 + +9:S + + + +n1->n9 + + +5 + + + +n2 + +2:P + + + +n2->n1 + + +10 + + + +n2->n5 + + +2 + + + +n7 + +7:S + + + +n2->n7 + + +6 + + + +n3 + +3:P + + + +n3->n1 + + +11 + + + +n6 + +6:D + + + +n3->n6 + + +3 + + + +n8 + +8:S + + + +n3->n8 + + +7 + + + +n4 + +4:P + + + +n4->n3 + + +12 + + + +n4->n6 + + +4 + + + +n4->n7 + + +8 + + + +n5->n1 + + +13 + + + +n6->n3 + + +14 + + + +n7->n8 + + +15 + + + +n8->n9 + + +16 + + + +n9->n9 + + +17 + + + diff --git a/v0.16.12/generated/sketches/cat_elements/index.html b/v0.16.12/generated/sketches/cat_elements/index.html new file mode 100644 index 000000000..f3c2ebd79 --- /dev/null +++ b/v0.16.12/generated/sketches/cat_elements/index.html @@ -0,0 +1,740 @@ + +The Category of Elements · Catlab.jl

The Category of Elements

A very useful construction in applied category theory is the Category of Elements, which is also called the Grothendieck construction. This is a very general technique in category theory, but we will look at how you can use it to explain why graphs are so useful in computer science. We have already seen that C-Sets are a model of relational databases that can be used to store data as a collection of interlocking tables. Relational databases are the bread and butter of the computing industry. Every company on earth uses software that is backed by a relational database. Most data that is not stored in a relational DB is often stored in some kind of graph data structure. This sketch will show how these approaches are interchangeable via the category of elements, which associates to every database instance a graph and a graph homomorphism into the schema of the graph.

using GATlab, Catlab.CategoricalAlgebra, Catlab.Graphs, Catlab.Graphics
+using Colors

Let's tell Catlab how to draw categories of elements.

function graph(el::Elements)
+  F = FinFunctor(Dict(:V => :El, :E => :Arr), Dict(:src => :src, :tgt => :tgt),
+                 SchGraph, SchElements)
+  ΔF = DataMigrationFunctor(F, Elements{Symbol}, Graph)
+  return ΔF(el)
+end
+
+safecolors(start, stop, len) = if len > 1
+  return hex.(range(start, stop=stop, length=len))
+else
+  return [hex.(start)]
+end
+
+function draw(f::Elements; kw...)
+  pg = to_graphviz_property_graph(graph(f);
+    node_labels=true, edge_labels=true, prog="neato", kw...)
+  vcolors = safecolors(colorant"#0021A5", colorant"#FA4616", nparts(f, :Ob))
+  ecolors = safecolors(colorant"#6C9AC3", colorant"#E28F41", nparts(f, :Hom))
+  for v in parts(f, :El)
+    fv = f[v, :πₑ]
+    set_vprops!(pg, v, Dict(:color => "#$(vcolors[fv])", :label=>"$v:$(f[v,[:πₑ, :nameo]])"))
+  end
+  for e in parts(f, :Arr)
+    fe = f[e, :πₐ]
+    set_eprops!(pg, e, Dict(:color => "#$(ecolors[fe])"))
+  end
+  to_graphviz(pg)
+end
+
+draw(g) = to_graphviz(g, node_labels=true, edge_labels=true, prog="neato")
draw (generic function with 2 methods)

The simplest schema

First we will look at discrete dynamical systems. The set S is our state space and the funct nxt associates to every state, the next state in the system. This is a deterministic dynamical system with finitely many states and discrete time.

@present SchDDS(FreeSchema) begin
+  S::Ob
+  nxt::Hom(S, S)
+end
+
+@acset_type DDS(SchDDS, index=[:nxt])
+
+fₓ = @acset DDS begin
+  S = 3
+  nxt = [2,3,1]
+end
+Main.__atexample__named__cat_elements.DDS {S:3} + + + + + + + + + + + + + + + + + + + + + +
Snxt
12
23
31
+
+

Now if you want to draw a DDS, you might think to draw each state as a vertex and the next relationship as an arrow from one state to the next state. If your intuition selected that representation, you have already discovered a special case of the category of elements

elᶠ = elements(fₓ)
+draw(graph(elᶠ))

As you are quite far in your category theoretic training, you are surely suspicious of the idea that you would construct the category of elements of a DDS and get a graph. We have a categorical construction, so your intuition should be saying "there should be some kind of morphism that goes with this object". And there is, the Elements of a C-Set X is a graph whose vertices are rows in the tables of X and whose edges are the foreign key relationships in X, along with a graph homomorphism into the schema C. We can draw this using the same color coding convention we used to draw graph homomorphisms.

draw(elᶠ)

We can scale up our DDS drawing too.

Fₓ = @acset DDS begin
+  S = 7
+  nxt = [2,3,1, 1,7,7,4]
+end
+draw(elements(Fₓ))

A category of elements derived from a C-Set is stored as a C-Set of on a different schema. You can see that it is the data of a graph homomorphism where the codomain graph has vertex and edge labels. The two projections πₑ and πₐ are the components of a natural transformation between graphs viewed as functors into Set. The names are attributes usually of type Symbol.

to_graphviz(SchElements)

In the case of a DDS, we have only one object and one morphism in the schema. Since the graph with one edge and one vertices is terminal in Graph, there is only one vertex and edge color being used.

The Elements of a Graph are its Vertices and Edges

In what might appear as primordial ooze, we can examine the category of elements of a graph. We will look at the commuting triangle graph. Notice how there are 3 vertices and three edges with each edge incident to 2 vertices.

g = @acset Graph begin
+  V = 3
+  E = 3
+  src = [1,2,1]
+  tgt = [2,3,3]
+end
+draw(g)

The category of elements has 6 vertices and 6 edges. The 6 vertices come from 3 vertices of type V and 3 vertices of type E. The 6 edges in this graph are 3 src relationships and 3 target relationships.

elᵍ = elements(g)
+draw(elᵍ)
+
+g = @acset Graph begin
+  V = 6
+  E = 7
+  src = [1,2,1,3,5,6,4]
+  tgt = [2,3,3,5,6,3,4]
+end
+draw(g)
+draw(elements(g))
Example block output

Notice that the 3 vertices of type E are interspersed between the 3 vertices of type V and vice versa. You can see that the normal visual syntax for a graph is more compact for the special case of graphs. However the category of elements works for any schema C.

Generality of the construction

Discrete Dynamical Systems and Graphs are clearly data structures from mathematics and so it would make sense that they have a clean representation in the categorical language. But how about a database schema that comes not from mathematics, but from software engineering. We turn to everyone's favorite database example, the HR database at a fictitious company.

@present SchCompany(FreeSchema) begin
+  (P, D, S)::Ob # Person, Department, Salary
+  worksin::Hom(P, D)    # Every Person works in a Department
+  makes::Hom(P, S)      # Every Person makes a Salary
+  reportsto::Hom(P, P)  # Every Person reports to a Person
+  managedby::Hom(D, P)  # Every Department is managed by a Person
+  leq::Hom(S,S)         # Salaries are a finite total order
+end
+
+@acset_type Company(SchCompany, index=[])
Main.Company

We can draw a company that has 4 people, 2 departments, and 3 distinct salaries.

cmpy = @acset Company begin
+  P = 4
+  D = 2
+  S = 3
+  worksin = [1,1,2,2]
+  makes = [3,1,2,1]
+  reportsto = [1, 1,1,3]
+  managedby = [1,3]
+  leq = [2,3,3]
+end
+Main.__atexample__named__cat_elements.Company {P:4, D:2, S:3} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Pworksinmakesreportsto
1131
2111
3221
4213
+ + + + + + + + + + + + + + + + + +
Dmanagedby
11
23
+ + + + + + + + + + + + + + + + + + + + + +
Sleq
12
23
33
+
+

A visualization of the elements of this functor is commonly described as a knowledge graph.

elᶜ = elements(cmpy)
+draw(elᶜ)
Example block output

The visualization of the category of elements isn't the most compact representation of data, but it is always an option. Once you know how to draw a graph homomorphism as a color-coded graph, you know how to draw any C-Set. The vertices and edges of the domain graph are the rows and fields of the C-Set, and the colors are from the vertices and edges of the schema C, viewed as a graph presenting the category. One thing you lose is the ability to represent path equations in C.

Reconstructing the C-Set from its category of elemnts

When looking at the graphical representation of the category of elements, you can see that the vertices are numbered sequentially within their vertex type. This order can be computed with the incident function in Catlab. There are inclusions of all the tables in the database instance into the global vertex set of the knowledge graph representation.

incident(elᶜ, :, :πₑ)
3-element Vector{AbstractVector{Int64}}:
+ [1, 2, 3, 4]
+ [5, 6]
+ [7, 8, 9]

The same goes for the edges (arrows) in the category of elements.

incident(elᶜ, :, :πₐ)
5-element Vector{AbstractVector{Int64}}:
+ [1, 2, 3, 4]
+ [5, 6, 7, 8]
+ [9, 10, 11, 12]
+ [13, 14]
+ [15, 16, 17]

From this information, you can reassemble the knowledge graph into a database. You use the codomain graph as the schema and then these two projections πₑ and πₐ to recover the instance data.

cset(T::Type, el::Elements) = begin
+  X = T()
+  ℓ = Dict{Int, Int}() # this map reverses the inclusions converting global element numbers into per-table numbers
+  for ob in parts(el, :Ob)
+    obname = el[ob, :nameo]
+    eltsob = incident(el, ob, :πₑ)
+    pts = add_parts!(X, obname, length(eltsob))
+    map(zip(pts, eltsob)) do (i,x)
+      ℓ[x] = i
+    end
+  end
+  for h in parts(el, :Hom)
+    nameh = el[h, :nameh]
+    arrₕ = incident(el, h, :πₐ)
+    doms = map(arrₕ) do e
+      ℓ[el[e, :src]]
+    end
+    codoms = map(arrₕ) do e
+      ℓ[el[e, :tgt]]
+    end
+    set_subpart!(X, doms, nameh, codoms)
+  end
+  return X
+end
cset (generic function with 1 method)

We can apply this algorithm to our company knowledge graph to recover our original DB.

cset(Company, elᶜ)
+cmpy == cset(Company, elᶜ)
true

Hopefully you see one reason why graphs are ubiquitous in computer science. Every relational database is isomorphic to a typed graph. You can generate this graph from the database and recover the database from the typed graph. So while knowledge graphs are great for ingesting data when you aren't sure about the structure and useful for some types of computation that involve long paths. You can always build your software on relational databases knowing that you can easily get access to all the graph algorithms by applying the Grothendieck construction.

The Slice-Elements Transform

An amazing fact about presheaf toposes is that they are closed under taking slices. In the graphs section of this documentation, you can find a description of bipartite and k-partite graphs as a morphisms into a clique. That definition is very mathematically pleasing because it gives you a category of partitioned graphs that are derived from commuting triangles in Graph. However, for application oriented practitioners, the definition of a bipartite graph as "a graph with two sets of vertices, where all the edges go between the groups with no edges within either group" is probably more explicit. For example a classic way to get a bipartite graph would be to look at the graph of authors and papers that those authors wrote. People write papers, people do not write people and papers do not write papers so the authorship graph is bipartite. These two equivalent definitions of a bipartite graph are related via an isomorphism you can find on the nlab. It shows that a slice category of [C,Set]/X is isomorphic to [El(X), Set] which is a cateogory of presheaves on a different schema. Catlab knows how to use this idea to turn a category of elements into a schema for a new category of presheaves. The two directions of the isomorphism are not yet implemented.

e = @acset Graph begin
+  V = 2
+  E = 1
+  src = 1
+  tgt = 2
+end
+
+draw(elements(e))
+
+SchBipartite = CatElements.presentation(elements(e))[1]
+to_graphviz(SchBipartite)
+
+@acset_type BipartiteGraph(SchBipartite)
+b = @acset BipartiteGraph begin
+  V_1 = 3
+  V_2 = 2
+  E_1 = 5
+  src_E_1 = [1,2,3,3,2]
+  tgt_E_1 = [1,2,2,1,1]
+end
+draw(elements(b))

As a very advanced exercise, you could try to implement one or both directions of the isomorphism above.

diff --git a/v0.16.12/generated/sketches/meets.ipynb b/v0.16.12/generated/sketches/meets.ipynb new file mode 100644 index 000000000..8594991cf --- /dev/null +++ b/v0.16.12/generated/sketches/meets.ipynb @@ -0,0 +1,926 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Meets in Preorders\n", + "\n", + "\n", + "Our first example of a concept defined by a universal mapping property is a meet respectively meet." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The first step is our Catlab imports" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Core: GeneratedFunctionStub\n", + "using Test\n", + "\n", + "using Catlab.Theories, Catlab.CategoricalAlgebra, Catlab.Graphics\n", + "import Catlab.Theories: compose\n", + "\n", + "using DataStructures" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "# Defining some basic preorders" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Presentation{Catlab.Theories.ThSchema.Meta.T, Symbol}(Catlab.Theories.FreeSchema, (Ob = Catlab.Theories.FreeSchema.Ob{:generator}[a₁, a₂, a₃, a₄], Hom = Catlab.Theories.FreeSchema.Hom{:generator}[f, g, h, k], AttrType = Catlab.Theories.FreeSchema.AttrType{:generator}[], Attr = Catlab.Theories.FreeSchema.Attr{:generator}[]), Dict(:a₃ => (:Ob => 3), :f => (:Hom => 1), :k => (:Hom => 4), :a₄ => (:Ob => 4), :a₁ => (:Ob => 1), :a₂ => (:Ob => 2), :g => (:Hom => 2), :h => (:Hom => 3)), Pair[])" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "@present P(FreeSchema) begin\n", + " (a₁,a₂,a₃,a₄)::Ob\n", + " f::Hom(a₁, a₂)\n", + " g::Hom(a₁, a₃)\n", + " h::Hom(a₂, a₄)\n", + " k::Hom(a₃, a₄)\n", + "end" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "We can draw a picture of our preorder as a Hasse Diagram." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₁\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₂\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₃\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₄\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"f\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"g\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"h\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"k\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "a₁\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "a₂\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "a₃\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "a₄\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "k\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(P)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "It will be convenient to program with our preorders based on the Hasse Diagram\n", + "represent as a labeled graph so we convert the Presentation{Schema, Symbol} into a FreeDigram.\n", + "FreeDiagrams are implemented as an ACSet which you can think of as an in-memory database.\n", + "ACSets are a key feature of Catlab that allow you to represent many data structures in a\n", + "common framework." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "FreeDiagram{Catlab.Theories.FreeSchema.Ob, Catlab.Theories.FreeSchema.Hom} {V:4, E:4, Ob:0, Hom:0}\n┌───┬────┐\n│\u001b[1m V │\u001b[1m ob │\n├───┼────┤\n│\u001b[1m 1 │ a₁ │\n│\u001b[1m 2 │ a₂ │\n│\u001b[1m 3 │ a₃ │\n│\u001b[1m 4 │ a₄ │\n└───┴────┘\n┌───┬─────┬─────┬─────┐\n│\u001b[1m E │\u001b[1m src │\u001b[1m tgt │\u001b[1m hom │\n├───┼─────┼─────┼─────┤\n│\u001b[1m 1 │ 1 │ 2 │ f │\n│\u001b[1m 2 │ 1 │ 3 │ g │\n│\u001b[1m 3 │ 2 │ 4 │ h │\n│\u001b[1m 4 │ 3 │ 4 │ k │\n└───┴─────┴─────┴─────┘\n", + "text/html": [ + "
\n", + "FreeDiagram{Catlab.Theories.FreeSchema.Ob, Catlab.Theories.FreeSchema.Hom} {V:4, E:4, Ob:0, Hom:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Vob
1a₁
2a₂
3a₃
4a₄
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Esrctgthom
112f
213g
324h
434k
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "g = FreeDiagram(P)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "To give ourselves a graph-like API for Hasse Diagrams, we define parents and children." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "children (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "parents(g, y::Int) = subpart(g, incident(g, y, :tgt), :src)\n", + "children(g, x::Int) = subpart(g, incident(g, x, :src), :tgt)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "We can compute upsets/downsets with breadth first search." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "bfs (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "function bfs(g, x::Int, f=children)\n", + " explored = falses(nparts(g, :V))\n", + " explored[x] = 1\n", + " q = Queue{Int}()\n", + " enqueue!(q, x)\n", + " while !isempty(q)\n", + " v = dequeue!(q)\n", + " S = f(g,v)\n", + " map(filter(s -> !explored[s], S)) do s\n", + " enqueue!(q, s)\n", + " end\n", + " explored[S] .= true\n", + " end\n", + " return findall(explored)\n", + "end" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "The upset of a preorder element is all the elements that come after it in the preorder." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "upset (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "upset(g,x) = bfs(g,x,children)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "The downset is the dual notion, which we compute by reversing the role of children and parents." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "4-element Vector{Int64}:\n 1\n 2\n 3\n 4" + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "downset(g,x) = bfs(g,x,parents)\n", + "\n", + "upset(g, 1)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "We can use upsets to define the less than or equal two relation implied by any Hasse Diagram" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "leq (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "function leq(g::FreeDiagram, x::Int, y::Int)\n", + " return y in upset(g, x)\n", + "end" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise 1\n", + "Define a more efficient algorithm for checking whether two elements satisfy the leq relation." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Multiple dispatch allows us to overload the leq function with another method for symbols." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "leq (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "function leq(g::FreeDiagram, x::Symbol, y::Symbol)\n", + " leq(g, incident(g, x, :ob), incident(g, y, :ob))\n", + "end" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "the meet of two elements is the largest element in the intersection of their downsets." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "meet (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "function meet(g::FreeDiagram, x::Int, y::Int)\n", + " U = downset(g, x) ∩ downset(g,y)\n", + " maxima(g, U)\n", + " return maximum(g, U)\n", + "end\n", + "\n", + "function meet(g::FreeDiagram, x, y)\n", + " meet(g, incident(g, x, :ob)[1], incident(g, y, :ob)[1])\n", + "end" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "assuming that D is a downset, the maxima are those elements whose children are disjoint from D." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "maximum (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "function maxima(g::FreeDiagram, D::Vector{Int})\n", + " X = Set(D)\n", + " M = filter(D) do x\n", + " Pₓ = children(g, x) ∩ X\n", + " length(Pₓ) == 0\n", + " end\n", + " return M\n", + "end\n", + "\n", + "function hastop(g::FreeDiagram, xs::Vector{Int})\n", + " length(maxima(g, xs)) == 1\n", + "end\n", + "\n", + "function maximum(g::FreeDiagram, xs::Vector{Int})\n", + " m = maxima(g, xs::Vector{Int})\n", + " if length(m) == 1\n", + " return m[1]\n", + " end\n", + " if length(m) > 1\n", + " all_iso = all(m) do a\n", + " Uₐ = downset(g, a)\n", + " a_le_allb = all(m) do b\n", + " b in Uₐ\n", + " end\n", + " return a_le_allb\n", + " end\n", + " if all_iso\n", + " return m[1]\n", + " end\n", + " end\n", + " return nothing\n", + "end" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "From the definition of minimum, you can see that when you want to do many leq queries\n", + "in sequence, you can reuse the upsets that you compute with bfs. This is a place where\n", + "mathematical abstractions don't work well with the operational needs of computer programming.\n", + "In a mathematical definition you can define x ≤ y as y ∈ upset(x), but in programming, that is\n", + "inefficient when you want to check a property like for all y in Y, x ≤ y. Programming requires\n", + "you to reason about not only the correctness of the code, but also the performance. Much of the\n", + "complexity of software engineering comes from the fact that computational performance requires\n", + "the programmers to break down their clean abstractions to optimize the code." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise 2\n", + "If you wanted to perform many x ≤ y queries in a loop, you might want to\n", + "precompute the matrix L where L[i,j] = 1 if and only if i ≤ j in the preorder P.\n", + "Implement an algorithm that performs this computation in O(V⋅E) time where V is the number of\n", + "elements in P and E is the number of edges in the corresponding FreeDiagram." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Testing it out" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Let's make sure we get the answers that we expect." + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Summary: | Pass Total Time\n", + "Upsets | 4 4 0.2s\n", + "Test Summary: | Pass Total Time\n", + "Downsets | 4 4 0.0s\n", + "Test Summary: | Pass Total Time\n", + "Meets | 6 6 0.1s\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": "Test.DefaultTestSet(\"Meets\", Any[], 6, false, false, true, 1.719011160159146e9, 1.719011160259244e9, false, \"/home/runner/work/Catlab.jl/Catlab.jl/docs/src/generated/sketches/meets.ipynb\")" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "using Test\n", + "@testset \"Upsets\" begin\n", + " @test upset(g, 3) == [3,4]\n", + " @test upset(g, 2) == [2,4]\n", + " @test upset(g, 1) == [1,2,3,4]\n", + " @test upset(g, 4) == [4]\n", + "end\n", + "@testset \"Downsets\" begin\n", + " @test downset(g, 3) == [1,3]\n", + " @test downset(g, 2) == [1,2]\n", + " @test downset(g, 4) == [1,2,3,4]\n", + " @test downset(g, 1) == [1]\n", + "end\n", + "\n", + "@testset \"Meets\" begin\n", + " @test meet(g, 2,3) == 1\n", + " @test meet(g, 1,2) == 1\n", + " @test meet(g, 3,4) == 3\n", + " @test meet(g, 1, 4) == 1\n", + " @test meet(g, 1, 1) == 1\n", + " @test meet(g, 2, 2) == 2\n", + "end" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "## Another Example:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Presentation{Catlab.Theories.ThSchema.Meta.T, Symbol}(Catlab.Theories.FreeSchema, (Ob = Catlab.Theories.FreeSchema.Ob{:generator}[a₁, a₂, a₃, a₄, a₅], Hom = Catlab.Theories.FreeSchema.Hom{:generator}[f, g, h, k, l], AttrType = Catlab.Theories.FreeSchema.AttrType{:generator}[], Attr = Catlab.Theories.FreeSchema.Attr{:generator}[]), Dict(:a₃ => (:Ob => 3), :f => (:Hom => 1), :l => (:Hom => 5), :k => (:Hom => 4), :a₄ => (:Ob => 4), :a₁ => (:Ob => 1), :a₂ => (:Ob => 2), :g => (:Hom => 2), :h => (:Hom => 3), :a₅ => (:Ob => 5)…), Pair[])" + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "@present P(FreeSchema) begin\n", + " (a₁,a₂,a₃,a₄, a₅)::Ob\n", + " f::Hom(a₁, a₂)\n", + " g::Hom(a₁, a₃)\n", + " h::Hom(a₂, a₄)\n", + " k::Hom(a₃, a₄)\n", + " l::Hom(a₅, a₂)\n", + "end" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "Which can be viewed as a picture:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₁\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₂\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₃\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₄\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"a₅\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"f\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"g\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"h\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"k\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"l\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "a₁\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "a₂\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "a₃\n", + "\n", + "\n", + "\n", + "n1->n3\n", + "\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "a₄\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "k\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "a₅\n", + "\n", + "\n", + "\n", + "n5->n2\n", + "\n", + "\n", + "l\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(P)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "Or, as tables:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "FreeDiagram{Catlab.Theories.FreeSchema.Ob, Catlab.Theories.FreeSchema.Hom} {V:5, E:5, Ob:0, Hom:0}\n┌───┬────┐\n│\u001b[1m V │\u001b[1m ob │\n├───┼────┤\n│\u001b[1m 1 │ a₁ │\n│\u001b[1m 2 │ a₂ │\n│\u001b[1m 3 │ a₃ │\n│\u001b[1m 4 │ a₄ │\n│\u001b[1m 5 │ a₅ │\n└───┴────┘\n┌───┬─────┬─────┬─────┐\n│\u001b[1m E │\u001b[1m src │\u001b[1m tgt │\u001b[1m hom │\n├───┼─────┼─────┼─────┤\n│\u001b[1m 1 │ 1 │ 2 │ f │\n│\u001b[1m 2 │ 1 │ 3 │ g │\n│\u001b[1m 3 │ 2 │ 4 │ h │\n│\u001b[1m 4 │ 3 │ 4 │ k │\n│\u001b[1m 5 │ 5 │ 2 │ l │\n└───┴─────┴─────┴─────┘\n", + "text/html": [ + "
\n", + "FreeDiagram{Catlab.Theories.FreeSchema.Ob, Catlab.Theories.FreeSchema.Hom} {V:5, E:5, Ob:0, Hom:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Vob
1a₁
2a₂
3a₃
4a₄
5a₅
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Esrctgthom
112f
213g
324h
434k
552l
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "g = FreeDiagram(P)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "### Test suite" + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Summary: | Pass Total Time\n", + "meets2 | 8 8 0.0s\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": "Test.DefaultTestSet(\"meets2\", Any[], 8, false, false, true, 1.719011160330657e9, 1.719011160330833e9, false, \"/home/runner/work/Catlab.jl/Catlab.jl/docs/src/generated/sketches/meets.ipynb\")" + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "@testset \"meets2\" begin\n", + " @test meet(g, 2,3) == 1\n", + " @test meet(g, 1,2) == 1\n", + " @test meet(g, 3,4) == 3\n", + " @test meet(g, 1, 4) == 1\n", + " @test meet(g, 1, 1) == 1\n", + " @test meet(g, 2, 2) == 2\n", + " @test meet(g, 3, 5) == nothing\n", + " @test meet(g, 2, 5) == 5\n", + "end" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise 3\n", + "Make bigger preorders to test corner cases in the above code.\n", + "If you find an example that breaks these implementations, please report it." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "### Exercise 4\n", + "Implement the dual constructions for joins." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/sketches/meets/index.html b/v0.16.12/generated/sketches/meets/index.html new file mode 100644 index 000000000..f1137c863 --- /dev/null +++ b/v0.16.12/generated/sketches/meets/index.html @@ -0,0 +1,398 @@ + +Meets in Preorders · Catlab.jl

Meets in Preorders

Our first example of a concept defined by a universal mapping property is a meet respectively meet.

The first step is our Catlab imports

using Core: GeneratedFunctionStub
+using Test
+
+using Catlab.Theories, Catlab.CategoricalAlgebra, Catlab.Graphics
+import Catlab.Theories: compose
+
+using DataStructures

Defining some basic preorders

@present P(FreeSchema) begin
+  (a₁,a₂,a₃,a₄)::Ob
+  f::Hom(a₁, a₂)
+  g::Hom(a₁, a₃)
+  h::Hom(a₂, a₄)
+  k::Hom(a₃, a₄)
+end
Presentation{Catlab.Theories.ThSchema.Meta.T, Symbol}(Catlab.Theories.FreeSchema, (Ob = Catlab.Theories.FreeSchema.Ob{:generator}[a₁, a₂, a₃, a₄], Hom = Catlab.Theories.FreeSchema.Hom{:generator}[f, g, h, k], AttrType = Catlab.Theories.FreeSchema.AttrType{:generator}[], Attr = Catlab.Theories.FreeSchema.Attr{:generator}[]), Dict(:a₃ => (:Ob => 3), :f => (:Hom => 1), :k => (:Hom => 4), :a₄ => (:Ob => 4), :a₁ => (:Ob => 1), :a₂ => (:Ob => 2), :g => (:Hom => 2), :h => (:Hom => 3)), Pair[])

We can draw a picture of our preorder as a Hasse Diagram.

to_graphviz(P)

It will be convenient to program with our preorders based on the Hasse Diagram represent as a labeled graph so we convert the Presentation{Schema, Symbol} into a FreeDigram. FreeDiagrams are implemented as an ACSet which you can think of as an in-memory database. ACSets are a key feature of Catlab that allow you to represent many data structures in a common framework.

g = FreeDiagram(P)
+FreeDiagram{Catlab.Theories.FreeSchema.Ob, Catlab.Theories.FreeSchema.Hom} {V:4, E:4, Ob:0, Hom:0} + + + + + + + + + + + + + + + + + + + + + + + + + +
Vob
1a₁
2a₂
3a₃
4a₄
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Esrctgthom
112f
213g
324h
434k
+
+

To give ourselves a graph-like API for Hasse Diagrams, we define parents and children.

parents(g, y::Int) = subpart(g, incident(g, y, :tgt), :src)
+children(g, x::Int) = subpart(g, incident(g, x, :src), :tgt)
children (generic function with 1 method)

We can compute upsets/downsets with breadth first search.

function bfs(g, x::Int, f=children)
+  explored = falses(nparts(g, :V))
+  explored[x] = 1
+  q = Queue{Int}()
+  enqueue!(q, x)
+  while !isempty(q)
+    v = dequeue!(q)
+    S = f(g,v)
+    map(filter(s -> !explored[s], S)) do s
+      enqueue!(q, s)
+    end
+    explored[S] .= true
+  end
+  return findall(explored)
+end
bfs (generic function with 2 methods)

The upset of a preorder element is all the elements that come after it in the preorder.

upset(g,x) = bfs(g,x,children)
upset (generic function with 1 method)

The downset is the dual notion, which we compute by reversing the role of children and parents.

downset(g,x) = bfs(g,x,parents)
+
+upset(g, 1)
4-element Vector{Int64}:
+ 1
+ 2
+ 3
+ 4

We can use upsets to define the less than or equal two relation implied by any Hasse Diagram

function leq(g::FreeDiagram, x::Int, y::Int)
+  return y in upset(g, x)
+end
leq (generic function with 1 method)

Exercise 1

Define a more efficient algorithm for checking whether two elements satisfy the leq relation.

Multiple dispatch allows us to overload the leq function with another method for symbols.

function leq(g::FreeDiagram, x::Symbol, y::Symbol)
+  leq(g, incident(g, x, :ob), incident(g, y, :ob))
+end
leq (generic function with 2 methods)

the meet of two elements is the largest element in the intersection of their downsets.

function meet(g::FreeDiagram, x::Int, y::Int)
+  U = downset(g, x) ∩ downset(g,y)
+  maxima(g, U)
+  return maximum(g, U)
+end
+
+function meet(g::FreeDiagram, x, y)
+  meet(g, incident(g, x, :ob)[1], incident(g, y, :ob)[1])
+end
meet (generic function with 2 methods)

assuming that D is a downset, the maxima are those elements whose children are disjoint from D.

function maxima(g::FreeDiagram, D::Vector{Int})
+  X = Set(D)
+  M = filter(D) do x
+    Pₓ = children(g, x) ∩ X
+    length(Pₓ) == 0
+  end
+  return M
+end
+
+function hastop(g::FreeDiagram, xs::Vector{Int})
+  length(maxima(g, xs)) == 1
+end
+
+function maximum(g::FreeDiagram, xs::Vector{Int})
+  m = maxima(g, xs::Vector{Int})
+  if length(m) == 1
+    return m[1]
+  end
+  if length(m) > 1
+    all_iso = all(m) do a
+      Uₐ = downset(g, a)
+      a_le_allb = all(m) do b
+        b in Uₐ
+      end
+      return a_le_allb
+    end
+    if all_iso
+      return  m[1]
+    end
+  end
+  return nothing
+end
maximum (generic function with 1 method)

From the definition of minimum, you can see that when you want to do many leq queries in sequence, you can reuse the upsets that you compute with bfs. This is a place where mathematical abstractions don't work well with the operational needs of computer programming. In a mathematical definition you can define x ≤ y as y ∈ upset(x), but in programming, that is inefficient when you want to check a property like for all y in Y, x ≤ y. Programming requires you to reason about not only the correctness of the code, but also the performance. Much of the complexity of software engineering comes from the fact that computational performance requires the programmers to break down their clean abstractions to optimize the code.

Exercise 2

If you wanted to perform many x ≤ y queries in a loop, you might want to precompute the matrix L where L[i,j] = 1 if and only if i ≤ j in the preorder P. Implement an algorithm that performs this computation in O(V⋅E) time where V is the number of elements in P and E is the number of edges in the corresponding FreeDiagram.

Testing it out

Let's make sure we get the answers that we expect.

using Test
+@testset "Upsets" begin
+  @test upset(g, 3) == [3,4]
+  @test upset(g, 2) == [2,4]
+  @test upset(g, 1) == [1,2,3,4]
+  @test upset(g, 4) == [4]
+end
+@testset "Downsets" begin
+  @test downset(g, 3) == [1,3]
+  @test downset(g, 2) == [1,2]
+  @test downset(g, 4) == [1,2,3,4]
+  @test downset(g, 1) == [1]
+end
+
+@testset "Meets" begin
+  @test meet(g, 2,3) == 1
+  @test meet(g, 1,2) == 1
+  @test meet(g, 3,4) == 3
+  @test meet(g, 1, 4) == 1
+  @test meet(g, 1, 1) == 1
+  @test meet(g, 2, 2) == 2
+end
Test.DefaultTestSet("Meets", Any[], 6, false, false, true, 1.719011223932895e9, 1.719011223979936e9, false, "meets.md")

Another Example:

@present P(FreeSchema) begin
+  (a₁,a₂,a₃,a₄, a₅)::Ob
+  f::Hom(a₁, a₂)
+  g::Hom(a₁, a₃)
+  h::Hom(a₂, a₄)
+  k::Hom(a₃, a₄)
+  l::Hom(a₅, a₂)
+end
Presentation{Catlab.Theories.ThSchema.Meta.T, Symbol}(Catlab.Theories.FreeSchema, (Ob = Catlab.Theories.FreeSchema.Ob{:generator}[a₁, a₂, a₃, a₄, a₅], Hom = Catlab.Theories.FreeSchema.Hom{:generator}[f, g, h, k, l], AttrType = Catlab.Theories.FreeSchema.AttrType{:generator}[], Attr = Catlab.Theories.FreeSchema.Attr{:generator}[]), Dict(:a₃ => (:Ob => 3), :f => (:Hom => 1), :l => (:Hom => 5), :k => (:Hom => 4), :a₄ => (:Ob => 4), :a₁ => (:Ob => 1), :a₂ => (:Ob => 2), :g => (:Hom => 2), :h => (:Hom => 3), :a₅ => (:Ob => 5)…), Pair[])

Which can be viewed as a picture:

to_graphviz(P)

Or, as tables:

g = FreeDiagram(P)
+FreeDiagram{Catlab.Theories.FreeSchema.Ob, Catlab.Theories.FreeSchema.Hom} {V:5, E:5, Ob:0, Hom:0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Vob
1a₁
2a₂
3a₃
4a₄
5a₅
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Esrctgthom
112f
213g
324h
434k
552l
+
+

Test suite

@testset "meets2" begin
+  @test meet(g, 2,3) == 1
+  @test meet(g, 1,2) == 1
+  @test meet(g, 3,4) == 3
+  @test meet(g, 1, 4) == 1
+  @test meet(g, 1, 1) == 1
+  @test meet(g, 2, 2) == 2
+  @test meet(g, 3, 5) == nothing
+  @test meet(g, 2, 5) == 5
+end
Test.DefaultTestSet("meets2", Any[], 8, false, false, true, 1.719011224038905e9, 1.719011224039058e9, false, "meets.md")

Exercise 3

Make bigger preorders to test corner cases in the above code. If you find an example that breaks these implementations, please report it.

Exercise 4

Implement the dual constructions for joins.

diff --git a/v0.16.12/generated/sketches/partitions.ipynb b/v0.16.12/generated/sketches/partitions.ipynb new file mode 100644 index 000000000..eee586c28 --- /dev/null +++ b/v0.16.12/generated/sketches/partitions.ipynb @@ -0,0 +1,589 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Partitions\n", + "\n", + "\n", + "Partitions are a categorical construction that we derive from sets and functions.\n", + "Given a set A, you can think of all of the ways to partition A into parts.\n", + "These ways of partitioning are isomorphic to equivalence relations R ⊆ A × A." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The first step is our Catlab imports" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Core: GeneratedFunctionStub\n", + "using Test\n", + "\n", + "using GATlab, Catlab.Theories, Catlab.CategoricalAlgebra\n", + "import Catlab.Theories: compose\n", + "using DataStructures\n", + "using PrettyTables\n", + "PrettyTables.pretty_table(f::FinFunction, name::Symbol=:f) =\n", + " pretty_table(OrderedDict(:x=>1:length(dom(f)), Symbol(\"$(name)(x)\")=>collect(f)))\n", + "using LaTeXStrings" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## FinSet: the category of Finite Sets\n", + "In FinSet the objects are sets n = {1...n} and the morphisms are functions between finite sets.\n", + "You can wrap a plain old Int into a finite set with the FinSet(n::Int) function. These sets will\n", + "serve as the domain and codomains of our functions." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "FinSet(4)" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "n = FinSet(3)\n", + "m = FinSet(4)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "once you have some sets, you can define functions between them. A FinFunction from n to m, f:n→m, can be specified as\n", + "an array of length n with elements from m." + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌───────┬───────┐\n", + "│ x │ f(x) │\n", + "│ Int64 │ Int64 │\n", + "├───────┼───────┤\n", + "│ 1 │ 2 │\n", + "│ 2 │ 4 │\n", + "│ 3 │ 3 │\n", + "└───────┴───────┘\n" + ] + } + ], + "cell_type": "code", + "source": [ + "f = FinFunction([2,4,3], n, m)\n", + "\n", + "pretty_table(f)" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "## Surjective maps\n", + "In order to use a map to represent a partition, we have to make sure that it is surjective.\n", + "Given a FinFunction, we can compute the preimage of any element in its codomain." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Int64[]" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "preimage(f, 2)\n", + "\n", + "preimage(f, 1)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "If the preimage is empty, then there is no element in the domain that maps to that element of the codomain.\n", + "This gives us a definition of surjective functions by asserting that all the preimages are nonempty.\n", + "Julia note: !p is the predicate x ↦ ¬p(x), f.(A) applies f to all of the elements in A." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "false" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "is_surjective(f::FinFunction) = all((!isempty).(preimage(f,i) for i in codom(f)))\n", + "is_surjective(f)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Our function f, wasn't surjective so it can't be used to induce a partition via its preimages.\n", + "Let's try again," + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌───────┬───────┐\n", + "│ x │ g(x) │\n", + "│ Int64 │ Int64 │\n", + "├───────┼───────┤\n", + "│ 1 │ 1 │\n", + "│ 2 │ 2 │\n", + "│ 3 │ 3 │\n", + "│ 4 │ 3 │\n", + "└───────┴───────┘\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "g = FinFunction([1,2,3,3], m, n)\n", + "pretty_table(g, :g)\n", + "is_surjective(g)" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "# Refinements of a Partition\n", + "When defining partitions classically as A = ∪ₚ Aₚ with p ≠ r ⟹ Aₚ ≠ Aᵣ,\n", + "it is not immediately obvious how to define comparisons between partitions.\n", + "With the \"a partition of A is a surjective map out of A\" definition, the comparisons\n", + "are obvious. The composition of surjective maps is surjective, so we can define\n", + "the refinement order in terms of a diagram in Set.\n", + "\n", + "You can see a graphical definition in [quiver](https://q.uiver.app/?q=WzAsMyxbMCwwLCJBIl0sWzMsMCwiUSJdLFszLDIsIlAiXSxbMSwyLCJoIiwwLHsic3R5bGUiOnsiaGVhZCI6eyJuYW1lIjoiZXBpIn19fV0sWzAsMSwiZiIsMCx7InN0eWxlIjp7ImhlYWQiOnsibmFtZSI6ImVwaSJ9fX1dLFswLDIsImciLDIseyJzdHlsZSI6eyJoZWFkIjp7Im5hbWUiOiJlcGkifX19XV0=)" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "TikzPictures.TikzPicture(\"A &&& Q \\\\\\\\\\n\\\\\\\\\\n&&& P\\n\\\\arrow[\\\"h\\\", two heads, from=1-4, to=3-4]\\n\\\\arrow[\\\"f\\\", two heads, from=1-1, to=1-4]\\n\\\\arrow[\\\"g\\\"', two heads, from=1-1, to=3-4]\", \"\", \"\\\\usepackage{tikz-cd}\\n% contents of quiver.sty\\n% `tikz-cd` is necessary to draw commutative diagrams.\\n\\\\RequirePackage{tikz-cd}\\n% `amssymb` is necessary for `\\\\lrcorner` and `\\\\ulcorner`.\\n\\\\RequirePackage{amssymb}\\n% `calc` is necessary to draw curved arrows.\\n\\\\usetikzlibrary{calc}\\n% `pathmorphing` is necessary to draw squiggly arrows.\\n\\\\usetikzlibrary{decorations.pathmorphing}\\n\\n% A TikZ style for curved arrows of a fixed height, due to AndréC.\\n\\\\tikzset{curve/.style={settings={#1},to path={(\\\\tikztostart)\\n .. controls (\\$(\\\\tikztostart)!\\\\pv{pos}!(\\\\tikztotarget)!\\\\pv{height}!270:(\\\\tikztotarget)\\$)\\n and (\\$(\\\\tikztostart)!1-\\\\pv{pos}!(\\\\tikztotarget)!\\\\pv{height}!270:(\\\\tikztotarget)\\$)\\n .. (\\\\tikztotarget)\\\\tikztonodes}},\\n settings/.code={\\\\tikzset{quiver/.cd,#1}\\n \\\\def\\\\pv##1{\\\\pgfkeysvalueof{/tikz/quiver/##1}}},\\n quiver/.cd,pos/.initial=0.35,height/.initial=0}\\n\\n% TikZ arrowhead/tail styles.\\n\\\\tikzset{tail reversed/.code={\\\\pgfsetarrowsstart{tikzcd to}}}\\n\\\\tikzset{2tail/.code={\\\\pgfsetarrowsstart{Implies[reversed]}}}\\n\\\\tikzset{2tail reversed/.code={\\\\pgfsetarrowsstart{Implies}}}\\n% TikZ arrow styles.\\n\\\\tikzset{no body/.style={/tikz/dash pattern=on 0 off 1mm}}\", \"tikzcd\", \"\", \"\", true, true)", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "using TikzCDs\n", + "\n", + "triangle = L\"\"\"\n", + "A &&& Q \\\\\n", + "\\\\\n", + "&&& P\n", + "\\arrow[\"h\", two heads, from=1-4, to=3-4]\n", + "\\arrow[\"f\", two heads, from=1-1, to=1-4]\n", + "\\arrow[\"g\"', two heads, from=1-1, to=3-4]\n", + "\"\"\";\n", + "\n", + "TikzCD(triangle, preamble=TikzCDs.Styles.Quiver)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "Let's take a look at an example:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌───────┬──────────┐\n", + "│ x │ (f⋅h)(x) │\n", + "│ Int64 │ Int64 │\n", + "├───────┼──────────┤\n", + "│ 1 │ 1 │\n", + "│ 2 │ 1 │\n", + "│ 3 │ 2 │\n", + "│ 4 │ 2 │\n", + "└───────┴──────────┘\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": "true" + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "A = FinSet(4)\n", + "Q = FinSet(3)\n", + "P = FinSet(2)\n", + "\n", + "f = FinFunction([1,2,3,3], A, Q)\n", + "g = FinFunction([1,1,2,2], A, P)\n", + "h = FinFunction([1,1,2], Q, P)\n", + "\n", + "@test_throws ErrorException compose(g,h) #Catlab checks the domains match\n", + "\n", + "pretty_table(compose(f,h), Symbol(\"(f⋅h)\"))\n", + "\n", + "compose(f,h) == g" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "This triangle commutes, so f is a refinement of g equivalently g is coarser than f." + ], + "metadata": {} + }, + { + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌───────┬───────────┐\n", + "│ x │ f⋅h⋅h′(x) │\n", + "│ Int64 │ Int64 │\n", + "├───────┼───────────┤\n", + "│ 1 │ 1 │\n", + "│ 2 │ 1 │\n", + "│ 3 │ 1 │\n", + "│ 4 │ 1 │\n", + "└───────┴───────────┘\n" + ] + } + ], + "cell_type": "code", + "source": [ + "h′ = FinFunction([1,1], P, FinSet(1))\n", + "\n", + "pretty_table(f⋅h⋅h′, Symbol(\"f⋅h⋅h′\"))" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "### Properties of refinements\n", + "We can show that refinement gives us a preorder on partitions directly from the\n", + "nice properties of surjective maps.\n", + "1. Reflexive: Any partition is a refinement of itself.\n", + "2. Transitive: If f ≤ g ≤ h as partitions, then f ≤ h\n", + "You can read these directly off the definition of refinements as a commutative\n", + "triangle in the category of (Set, Surjections).\n", + "You can edit this diagram in [quiver](https://q.uiver.app/?q=WzAsNCxbMCwwLCJBIl0sWzMsMCwiUSJdLFszLDIsIlAiXSxbMyw0LCJRXlxccHJpbWUiXSxbMSwyLCJoIl0sWzAsMSwiZiIsMCx7InN0eWxlIjp7ImhlYWQiOnsibmFtZSI6ImVwaSJ9fX1dLFswLDIsImciLDIseyJzdHlsZSI6eyJoZWFkIjp7Im5hbWUiOiJlcGkifX19XSxbMiwzLCJoXlxccHJpbWUiXSxbMCwzLCJmXFxjZG90IGhcXGNkb3QgaF5cXHByaW1lID0gZ1xcY2RvdCBoXlxccHJpbWUiLDIseyJzdHlsZSI6eyJoZWFkIjp7Im5hbWUiOiJlcGkifX19XV0=)" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "TikzPictures.TikzPicture(\"A &&& Q \\\\\\\\\\n\\\\\\\\\\n&&& P \\\\\\\\\\n\\\\\\\\\\n&&& {Q^\\\\prime}\\n\\\\arrow[\\\"h\\\", from=1-4, to=3-4]\\n\\\\arrow[\\\"f\\\", two heads, from=1-1, to=1-4]\\n\\\\arrow[\\\"g\\\"', two heads, from=1-1, to=3-4]\\n\\\\arrow[\\\"{h^\\\\prime}\\\", from=3-4, to=5-4]\\n\\\\arrow[\\\"{f\\\\cdot h\\\\cdot h^\\\\prime = g\\\\cdot h^\\\\prime}\\\"', two heads, from=1-1, to=5-4]\", \"\", \"\\\\usepackage{tikz-cd}\\n% contents of quiver.sty\\n% `tikz-cd` is necessary to draw commutative diagrams.\\n\\\\RequirePackage{tikz-cd}\\n% `amssymb` is necessary for `\\\\lrcorner` and `\\\\ulcorner`.\\n\\\\RequirePackage{amssymb}\\n% `calc` is necessary to draw curved arrows.\\n\\\\usetikzlibrary{calc}\\n% `pathmorphing` is necessary to draw squiggly arrows.\\n\\\\usetikzlibrary{decorations.pathmorphing}\\n\\n% A TikZ style for curved arrows of a fixed height, due to AndréC.\\n\\\\tikzset{curve/.style={settings={#1},to path={(\\\\tikztostart)\\n .. controls (\\$(\\\\tikztostart)!\\\\pv{pos}!(\\\\tikztotarget)!\\\\pv{height}!270:(\\\\tikztotarget)\\$)\\n and (\\$(\\\\tikztostart)!1-\\\\pv{pos}!(\\\\tikztotarget)!\\\\pv{height}!270:(\\\\tikztotarget)\\$)\\n .. (\\\\tikztotarget)\\\\tikztonodes}},\\n settings/.code={\\\\tikzset{quiver/.cd,#1}\\n \\\\def\\\\pv##1{\\\\pgfkeysvalueof{/tikz/quiver/##1}}},\\n quiver/.cd,pos/.initial=0.35,height/.initial=0}\\n\\n% TikZ arrowhead/tail styles.\\n\\\\tikzset{tail reversed/.code={\\\\pgfsetarrowsstart{tikzcd to}}}\\n\\\\tikzset{2tail/.code={\\\\pgfsetarrowsstart{Implies[reversed]}}}\\n\\\\tikzset{2tail reversed/.code={\\\\pgfsetarrowsstart{Implies}}}\\n% TikZ arrow styles.\\n\\\\tikzset{no body/.style={/tikz/dash pattern=on 0 off 1mm}}\", \"tikzcd\", \"\", \"\", true, true)", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "refinement = L\"\"\"\n", + "A &&& Q \\\\\n", + "\\\\\n", + "&&& P \\\\\n", + "\\\\\n", + "&&& {Q^\\prime}\n", + "\\arrow[\"h\", from=1-4, to=3-4]\n", + "\\arrow[\"f\", two heads, from=1-1, to=1-4]\n", + "\\arrow[\"g\"', two heads, from=1-1, to=3-4]\n", + "\\arrow[\"{h^\\prime}\", from=3-4, to=5-4]\n", + "\\arrow[\"{f\\cdot h\\cdot h^\\prime = g\\cdot h^\\prime}\"', two heads, from=1-1, to=5-4]\n", + "\"\"\";\n", + "\n", + "TikzCD(refinement, preamble=TikzCDs.Styles.Quiver)" + ], + "metadata": {}, + "execution_count": 10 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/sketches/partitions/72f46334.svg b/v0.16.12/generated/sketches/partitions/72f46334.svg new file mode 100644 index 000000000..497c245ef --- /dev/null +++ b/v0.16.12/generated/sketches/partitions/72f46334.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/sketches/partitions/9fc70db0.svg b/v0.16.12/generated/sketches/partitions/9fc70db0.svg new file mode 100644 index 000000000..25bae4dc1 --- /dev/null +++ b/v0.16.12/generated/sketches/partitions/9fc70db0.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.16.12/generated/sketches/partitions/index.html b/v0.16.12/generated/sketches/partitions/index.html new file mode 100644 index 000000000..082fd2cb0 --- /dev/null +++ b/v0.16.12/generated/sketches/partitions/index.html @@ -0,0 +1,72 @@ + +Partitions · Catlab.jl

Partitions

Partitions are a categorical construction that we derive from sets and functions. Given a set A, you can think of all of the ways to partition A into parts. These ways of partitioning are isomorphic to equivalence relations R ⊆ A × A.

The first step is our Catlab imports

using Core: GeneratedFunctionStub
+using Test
+
+using GATlab, Catlab.Theories, Catlab.CategoricalAlgebra
+import Catlab.Theories: compose
+using DataStructures
+using PrettyTables
+PrettyTables.pretty_table(f::FinFunction, name::Symbol=:f) =
+  pretty_table(OrderedDict(:x=>1:length(dom(f)), Symbol("$(name)(x)")=>collect(f)))
+using LaTeXStrings

FinSet: the category of Finite Sets

In FinSet the objects are sets n = {1...n} and the morphisms are functions between finite sets. You can wrap a plain old Int into a finite set with the FinSet(n::Int) function. These sets will serve as the domain and codomains of our functions.

n = FinSet(3)
+m = FinSet(4)
FinSet(4)

once you have some sets, you can define functions between them. A FinFunction from n to m, f:n→m, can be specified as an array of length n with elements from m.

f = FinFunction([2,4,3], n, m)
+
+pretty_table(f)
┌───────┬───────┐
+│     x │  f(x) │
+│ Int64 │ Int64 │
+├───────┼───────┤
+│     1 │     2 │
+│     2 │     4 │
+│     3 │     3 │
+└───────┴───────┘

Surjective maps

In order to use a map to represent a partition, we have to make sure that it is surjective. Given a FinFunction, we can compute the preimage of any element in its codomain.

preimage(f, 2)
+
+preimage(f, 1)
Int64[]

If the preimage is empty, then there is no element in the domain that maps to that element of the codomain. This gives us a definition of surjective functions by asserting that all the preimages are nonempty. Julia note: !p is the predicate x ↦ ¬p(x), f.(A) applies f to all of the elements in A.

is_surjective(f::FinFunction) = all((!isempty).(preimage(f,i) for i in codom(f)))
+is_surjective(f)
false

Our function f, wasn't surjective so it can't be used to induce a partition via its preimages. Let's try again,

g = FinFunction([1,2,3,3], m, n)
+pretty_table(g, :g)
+is_surjective(g)
true

Refinements of a Partition

When defining partitions classically as A = ∪ₚ Aₚ with p ≠ r ⟹ Aₚ ≠ Aᵣ, it is not immediately obvious how to define comparisons between partitions. With the "a partition of A is a surjective map out of A" definition, the comparisons are obvious. The composition of surjective maps is surjective, so we can define the refinement order in terms of a diagram in Set.

You can see a graphical definition in quiver

using TikzCDs
+
+triangle = L"""
+A &&& Q \\
+\\
+&&& P
+\arrow["h", two heads, from=1-4, to=3-4]
+\arrow["f", two heads, from=1-1, to=1-4]
+\arrow["g"', two heads, from=1-1, to=3-4]
+""";
+
+TikzCD(triangle, preamble=TikzCDs.Styles.Quiver)
Example block output

Let's take a look at an example:

A = FinSet(4)
+Q = FinSet(3)
+P = FinSet(2)
+
+f = FinFunction([1,2,3,3], A, Q)
+g = FinFunction([1,1,2,2], A, P)
+h = FinFunction([1,1,2], Q, P)
+
+@test_throws ErrorException compose(g,h) #Catlab checks the domains match
+
+pretty_table(compose(f,h), Symbol("(f⋅h)"))
+
+compose(f,h) == g
true

This triangle commutes, so f is a refinement of g equivalently g is coarser than f.

h′ = FinFunction([1,1], P, FinSet(1))
+
+pretty_table(f⋅h⋅h′, Symbol("f⋅h⋅h′"))
┌───────┬───────────┐
+│     x │ f⋅h⋅h′(x) │
+│ Int64 │     Int64 │
+├───────┼───────────┤
+│     1 │         1 │
+│     2 │         1 │
+│     3 │         1 │
+│     4 │         1 │
+└───────┴───────────┘

Properties of refinements

We can show that refinement gives us a preorder on partitions directly from the nice properties of surjective maps.

  1. Reflexive: Any partition is a refinement of itself.
  2. Transitive: If f ≤ g ≤ h as partitions, then f ≤ h

You can read these directly off the definition of refinements as a commutative triangle in the category of (Set, Surjections). You can edit this diagram in quiver

refinement = L"""
+A &&& Q \\
+\\
+&&& P \\
+\\
+&&& {Q^\prime}
+\arrow["h", from=1-4, to=3-4]
+\arrow["f", two heads, from=1-1, to=1-4]
+\arrow["g"', two heads, from=1-1, to=3-4]
+\arrow["{h^\prime}", from=3-4, to=5-4]
+\arrow["{f\cdot h\cdot h^\prime = g\cdot h^\prime}"', two heads, from=1-1, to=5-4]
+""";
+
+TikzCD(refinement, preamble=TikzCDs.Styles.Quiver)
Example block output
diff --git a/v0.16.12/generated/sketches/preorders.ipynb b/v0.16.12/generated/sketches/preorders.ipynb new file mode 100644 index 000000000..a6285aef7 --- /dev/null +++ b/v0.16.12/generated/sketches/preorders.ipynb @@ -0,0 +1,679 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Preorders\n", + "\n", + "\n", + "Many of the ideas in category theory can be viewed as generalizations of\n", + "preorders or monoids. This sketch shows some features of Catlab through the\n", + "lens of preorders.\n", + "You will see examples of defining GATs, Presentations, Syntax, and Functors.\n", + "These are illustrated with preorders or thin categories, which are particularly\n", + "simple cases of categories." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Core: GeneratedFunctionStub\n", + "using Test\n", + "\n", + "using Catlab.Theories, Catlab.CategoricalAlgebra\n", + "import Catlab.Theories: compose" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "# Definition of a Preorder formalized as a GAT\n", + "\n", + "The following definitions can be found in the `Catlab.Theories` module.\n", + "\n", + "```julia\n", + "\"\"\" Theory of *preorders*\n", + "\n", + "Preorders encode the axioms of reflexivity and transitivity as term constructors.\n", + "\"\"\"\n", + "@theory Preorder{El,Leq} begin\n", + " El::TYPE\n", + " Leq(lhs::El, rhs::El)::TYPE\n", + " @op (≤) := Leq\n", + "\n", + " # Preorder axioms are lifted to term constructors in the GAT.\n", + " reflexive(A::El)::(A≤A) # ∀ A there is a term reflexive(A) which implies A≤A\n", + " transitive(f::(A≤B), g::(B≤C))::(A≤C) ⊣ (A::El, B::El, C::El)\n", + "\n", + " # Axioms of the GAT are equivalences on terms or simplification rules in the logic\n", + " f == g ⊣ (A::El, B::El, f::(A≤B), g::(A≤B))\n", + " # Read as (f⟹ A≤B ∧ g⟹ A≤B) ⟹ f ≡ g\n", + "end\n", + "```\n", + "\n", + "# Preorders are Thin Categories\n", + "\n", + "Definition of a thin category\n", + "```julia\n", + "@theory ThinCategory{Ob,Hom} <: Category{Ob,Hom} begin\n", + " f == g ⊣ (A::Ob, B::Ob, f::Hom(A,B), g::Hom(A,B))\n", + "end\n", + "```\n", + "\n", + "of course this definition extends the GAT of categories\n", + "\n", + "```julia\n", + "@theory Category{Ob,Hom} begin\n", + " # Unicode aliases.\n", + " @op begin\n", + " (→) := Hom\n", + " (⋅) := compose\n", + " end\n", + "\n", + " \"\"\" Object in a category \"\"\"\n", + " Ob::TYPE\n", + "\n", + " \"\"\" Morphism in a category \"\"\"\n", + " Hom(dom::Ob,codom::Ob)::TYPE\n", + "\n", + " id(A::Ob)::(A → A)\n", + " compose(f::(A → B), g::(B → C))::(A → C) ⊣ (A::Ob, B::Ob, C::Ob)\n", + "\n", + " # Category axioms.\n", + " ((f ⋅ g) ⋅ h == f ⋅ (g ⋅ h)\n", + " ⊣ (A::Ob, B::Ob, C::Ob, D::Ob, f::(A → B), g::(B → C), h::(C → D)))\n", + " f ⋅ id(B) == f ⊣ (A::Ob, B::Ob, f::(A → B))\n", + " id(A) ⋅ f == f ⊣ (A::Ob, B::Ob, f::(A → B))\n", + "end\n", + "```\n", + "\n", + "Exercise: construct an isomorphism between the theory of thin categories and\n", + "the theory of preorders. Show that they have the same models." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Once you have a GAT defined using the `@theory` macro, you can define presentations,\n", + "which are logical syntax for giving examples of the theory. The GAT contains type\n", + "and term constructors that you can use to write expressions. A presentation uses\n", + "those expressions to create a specific example of the theory. We define `P` to be a preorder\n", + "with 3 elements and 2 ≤ relationships." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Presentation{Catlab.Theories.ThThinCategory.Meta.T, Symbol}(Catlab.Theories.FreeThinCategory, (Ob = Catlab.Theories.FreeThinCategory.Ob{:generator}[X, Y, Z], Hom = Catlab.Theories.FreeThinCategory.Hom{:generator}[f, g]), Dict(:Z => (:Ob => 3), :f => (:Hom => 1), :X => (:Ob => 1), :Y => (:Ob => 2), :g => (:Hom => 2)), Pair[])" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "@present P(FreeThinCategory) begin\n", + " (X,Y,Z)::Ob\n", + " f::Hom(X,Y)\n", + " g::Hom(Y,Z)\n", + "end" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "another example" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Presentation{Catlab.Theories.ThThinCategory.Meta.T, Symbol}(Catlab.Theories.FreeThinCategory, (Ob = Catlab.Theories.FreeThinCategory.Ob{:generator}[X, Y, Z, Y′], Hom = Catlab.Theories.FreeThinCategory.Hom{:generator}[f, g, f′, g′]), Dict(:Z => (:Ob => 3), :f => (:Hom => 1), :f′ => (:Hom => 3), :X => (:Ob => 1), :Y => (:Ob => 2), :g => (:Hom => 2), :Y′ => (:Ob => 4), :g′ => (:Hom => 4)), Pair[])" + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "@present Q(FreeThinCategory) begin\n", + " (X,Y,Z)::Ob\n", + " f::Hom(X,Y)\n", + " g::Hom(Y,Z)\n", + " Y′::Ob\n", + " f′::Hom(X,Y′)\n", + " g′::Hom(Y′,Z)\n", + "end" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Exercise: draw the Hasse diagrams for these preorders by hand." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "# Composition is transitivity\n", + "expressions in the presentation are paths in the Hasse Diagram" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "compose (generic function with 76 methods)" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "function compose(P::Presentation, vs::Vector{Symbol})\n", + " compose(collect(generator(P, v) for v in vs))\n", + "end" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "expressions are represented at expression trees" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "f⋅g: X → Z", + "text/latex": "$f \\cdot g : X \\to Z$" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "ex = compose(P, [:f, :g])" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "the head of an expression is the root of the expression tree" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": ":compose" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "head(ex)" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "the julia type of the expression" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Theories.FreeThinCategory.Hom{:compose}" + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "typeof(ex)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "the GAT type of the expression" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": ":Hom" + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "gat_typeof(ex)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "the parameters of the GAT Type" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2-element Vector{GATExpr}:\n X\n Z" + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "gat_type_args(ex)" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "in any thin category there is at most one morphism between any pair of objects.\n", + "In symbols: ex₁::Hom(X,Y) ∧ ex₂::Hom(X,Y) ⟹ ex₁ == ex₂" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "function thinequal(ex₁::FreeThinCategory.Hom, ex₂::FreeThinCategory.Hom)\n", + " dom(ex₁) == dom(ex₂) && codom(ex₁) == codom(ex₂)\n", + "end\n", + "\n", + "@test thinequal(ex, compose(P, [:f,:g])⋅id(generator(P,:Z)))" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "Thinking in terms of preorders, the composite f⋅g::Hom(X,Z) is a proof that X ≤ Z\n", + "in logical notation you would say f::Hom(X,Y) and g::Hom(Y,Z) ⊢ f⋅g::Hom(X,Z)\n", + "given a proof that X≤Y and a proof of Y≤Z then ⋅ will create a proof of X≤Z\n", + "by composing the proofs sequentially like chaining inequalities in math\n", + "a key aspect of category theory is that you want to work constructively\n", + "you don't want to know that there exists a composite, you want to hold onto that composite.\n", + "in programming, the way that you hold onto things is putting data into data structures.\n", + "While computers can access things by offset or addresses, programmers want to use names\n", + "so when we prove in P that X≤Z, we name that proof by adding it as a generator" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "f⋅g: X → Z", + "text/latex": "$f \\cdot g : X \\to Z$" + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "@present P₂(FreeThinCategory) begin\n", + " (X,Y,Z)::Ob\n", + " f::Hom(X,Y)\n", + " g::Hom(Y,Z)\n", + " h::Hom(X,Z)\n", + "end\n", + "\n", + "ex = compose(P₂, [:f, :g])" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "Now that we have a name for h, we can see that thinequal knows that f⋅g == h because\n", + "according to the definition of a thin category, any two morphisms with the same\n", + "domain and codomain are equal." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "@test thinequal(ex, generator(P₂, :h))" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "There is an imperative interface to manipulating presentations by mutating them for this purpose" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "6-element Vector{Any}:\n X\n Y\n Z\n f: X → Y\n g: Y → Z\n h: X → Z" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "P₂′ = copy(P)\n", + "add_generator!(P₂′, Hom(:h, P[:X], P[:Z]))\n", + "generators(P₂′)" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "We could avoid this naming the homs situation by giving all the homs the same name\n", + "however, then when you tried to write down a morphism, you wouldn't be able to refer\n", + "to a specific one by name, because they are all named ≤." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "4-element Vector{Any}:\n x\n y\n z\n ≤: x → y" + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "@present R(FreeThinCategory) begin\n", + " (x,y,z)::Ob\n", + " (≤)::Hom(x,y)\n", + "end\n", + "generators(R)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "Catlab won't let you make a presentation where the homs have the same exact name.\n", + "So, this will error:\n", + "\n", + "```julia\n", + "@present Q(FreeThinCategory) begin\n", + " (x,y,z)::Ob\n", + " (≤)::Hom(x,y)\n", + " (≤)::Hom(y,z)\n", + " (≤)::Hom(x,z)\n", + "end\n", + "```\n", + "\n", + "However, you can omit the names for homs with the following syntax, which is useful for thin categories.\n", + "\n", + "```julia\n", + "@present Q(FreeThinCategory) begin\n", + " (x,y,z)::Ob\n", + " ::Hom(x,y)\n", + " ::Hom(y,z)\n", + " ::Hom(x,z)\n", + "end\n", + "```" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "In a thin category, all the homs with the same domain and codomain are the same,\n", + "so why don't we name them by their the domain and codomain and then use the property\n", + "that any two homs with the same name are the same to encode the thinness. This is what\n", + "the Hasse diagram representation does for us. The edges in the diagram are encoding the\n", + "presentation data into a combinatorial object that we can visualize. There are many\n", + "reasons to encode a logical structure into a combinatorial strucuture, one is that\n", + "we generally have ways of drawing combinatorial objects that convey their saliant structure\n", + "and enable visual reasoning. Another is algorithms, isomorphism between the combinatorial representations\n", + "provide some of the isomorphisms between the logical structures. in this case, a graph homomorphism between Hasse Diagrams\n", + "construct isomorphisms between the preorders they present. The converse is not true since there can be many Graphs\n", + "that present the same preorder." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "# Monotone Maps" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "a generator is in the set of homs if it is in the list of generators" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "in_homs (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "in_homs(f::FreeThinCategory.Hom{:generator}, C::FinCat) =\n", + " f in hom_generators(C)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "a composite hom is in the list set of homs if all of its components are." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "in_homs (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "in_homs(f::FreeThinCategory.Hom{:compose}, C::FinCat) =\n", + " all(fᵢ->in_homs(fᵢ, C), args(f))" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "we can check if a map is functorial, which is called monotone for preorders.\n", + "1. make sure all the objects in the domain are sent to objects in the codomain\n", + "2. make sure all the homs are sent to homs in the codomain\n", + "3. check that the domains and codomainss of the homs match" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "function is_functorial(F::FinFunctor)\n", + " pₒ = map(ob_generators(dom(F))) do X\n", + " F(X) in ob_generators(codom(F))\n", + " end |> all\n", + "\n", + " pₕ = map(hom_generators(dom(F))) do f\n", + " in_homs(F(f), codom(F))\n", + " end |> all\n", + "\n", + " pᵩ = map(hom_generators(dom(F))) do f\n", + " FX = F(dom(f))\n", + " FY = F(codom(f))\n", + " Ff = F(f)\n", + " dom(Ff) == FX && codom(Ff) == FY\n", + " end |> all\n", + " return pₒ && pₕ && pᵩ\n", + "end\n", + "\n", + "@present Q(FreeThinCategory) begin\n", + " (a,b,c,d)::Ob\n", + " ab::Hom(a,b)\n", + " bc::Hom(b,c)\n", + " cd::Hom(c,d)\n", + "end\n", + "generators(Q)\n", + "\n", + "Fₒ = Dict(:X=>:a, :Y=>:b, :Z=>:c)\n", + "Fₕ = Dict(:f=>:ab, :g=>:bc)\n", + "F = FinFunctor(Fₒ, Fₕ, P, Q)\n", + "@test is_functorial(F)\n", + "\n", + "Fₒ = Dict(:X=>:a, :Y=>:b, :Z=>:d)\n", + "Fₕ = Dict(:f=>:ab, :g=>[:bc, :cd])\n", + "F = FinFunctor(Fₒ, Fₕ, P, Q)\n", + "@test is_functorial(F)\n", + "\n", + "\n", + "Fₒ = Dict(:X=>:a, :Y=>:b, :Z=>:c)\n", + "Fₕ = Dict(:f=>:ab, :g=>[:bc, :cd])\n", + "F = FinFunctor(Fₒ, Fₕ, P, Q)\n", + "@test !is_functorial(F)" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "Monotone maps are functors for thin categories. One of the benefits of\n", + "category theory is that we find abstractions that work in multiple domains.\n", + "The abstraction of preserving the domains and codomains of morphisms is\n", + "a key abstraction that we can use to define many notions in mathematics." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/sketches/preorders/index.html b/v0.16.12/generated/sketches/preorders/index.html new file mode 100644 index 000000000..9f798ef89 --- /dev/null +++ b/v0.16.12/generated/sketches/preorders/index.html @@ -0,0 +1,139 @@ + +Preorders · Catlab.jl

Preorders

Many of the ideas in category theory can be viewed as generalizations of preorders or monoids. This sketch shows some features of Catlab through the lens of preorders. You will see examples of defining GATs, Presentations, Syntax, and Functors. These are illustrated with preorders or thin categories, which are particularly simple cases of categories.

using Core: GeneratedFunctionStub
+using Test
+
+using Catlab.Theories, Catlab.CategoricalAlgebra
+import Catlab.Theories: compose

Definition of a Preorder formalized as a GAT

The following definitions can be found in the Catlab.Theories module.

""" Theory of *preorders*
+
+Preorders encode the axioms of reflexivity and transitivity as term constructors.
+"""
+@theory Preorder{El,Leq} begin
+  El::TYPE
+  Leq(lhs::El, rhs::El)::TYPE
+  @op (≤) := Leq
+
+  # Preorder axioms are lifted to term constructors in the GAT.
+  reflexive(A::El)::(A≤A) # ∀ A there is a term reflexive(A) which implies A≤A
+  transitive(f::(A≤B), g::(B≤C))::(A≤C) ⊣ (A::El, B::El, C::El)
+
+  # Axioms of the GAT are equivalences on terms or simplification rules in the logic
+  f == g ⊣ (A::El, B::El, f::(A≤B), g::(A≤B))
+  # Read as (f⟹ A≤B ∧ g⟹ A≤B) ⟹ f ≡ g
+end

Preorders are Thin Categories

Definition of a thin category

@theory ThinCategory{Ob,Hom} <: Category{Ob,Hom} begin
+  f == g ⊣ (A::Ob, B::Ob, f::Hom(A,B), g::Hom(A,B))
+end

of course this definition extends the GAT of categories

@theory Category{Ob,Hom} begin
+  # Unicode aliases.
+  @op begin
+  (→) := Hom
+  (⋅) := compose
+  end
+
+  """ Object in a category """
+  Ob::TYPE
+
+  """ Morphism in a category """
+  Hom(dom::Ob,codom::Ob)::TYPE
+
+  id(A::Ob)::(A → A)
+  compose(f::(A → B), g::(B → C))::(A → C) ⊣ (A::Ob, B::Ob, C::Ob)
+
+  # Category axioms.
+  ((f ⋅ g) ⋅ h == f ⋅ (g ⋅ h)
+  ⊣ (A::Ob, B::Ob, C::Ob, D::Ob, f::(A → B), g::(B → C), h::(C → D)))
+  f ⋅ id(B) == f ⊣ (A::Ob, B::Ob, f::(A → B))
+  id(A) ⋅ f == f ⊣ (A::Ob, B::Ob, f::(A → B))
+end

Exercise: construct an isomorphism between the theory of thin categories and the theory of preorders. Show that they have the same models.

Once you have a GAT defined using the @theory macro, you can define presentations, which are logical syntax for giving examples of the theory. The GAT contains type and term constructors that you can use to write expressions. A presentation uses those expressions to create a specific example of the theory. We define P to be a preorder with 3 elements and 2 ≤ relationships.

@present P(FreeThinCategory) begin
+  (X,Y,Z)::Ob
+  f::Hom(X,Y)
+  g::Hom(Y,Z)
+end
Presentation{Catlab.Theories.ThThinCategory.Meta.T, Symbol}(Catlab.Theories.FreeThinCategory, (Ob = Catlab.Theories.FreeThinCategory.Ob{:generator}[X, Y, Z], Hom = Catlab.Theories.FreeThinCategory.Hom{:generator}[f, g]), Dict(:Z => (:Ob => 3), :f => (:Hom => 1), :X => (:Ob => 1), :Y => (:Ob => 2), :g => (:Hom => 2)), Pair[])

another example

@present Q(FreeThinCategory) begin
+  (X,Y,Z)::Ob
+  f::Hom(X,Y)
+  g::Hom(Y,Z)
+  Y′::Ob
+  f′::Hom(X,Y′)
+  g′::Hom(Y′,Z)
+end
Presentation{Catlab.Theories.ThThinCategory.Meta.T, Symbol}(Catlab.Theories.FreeThinCategory, (Ob = Catlab.Theories.FreeThinCategory.Ob{:generator}[X, Y, Z, Y′], Hom = Catlab.Theories.FreeThinCategory.Hom{:generator}[f, g, f′, g′]), Dict(:Z => (:Ob => 3), :f => (:Hom => 1), :f′ => (:Hom => 3), :X => (:Ob => 1), :Y => (:Ob => 2), :g => (:Hom => 2), :Y′ => (:Ob => 4), :g′ => (:Hom => 4)), Pair[])

Exercise: draw the Hasse diagrams for these preorders by hand.

Composition is transitivity

expressions in the presentation are paths in the Hasse Diagram

function compose(P::Presentation, vs::Vector{Symbol})
+  compose(collect(generator(P, v) for v in vs))
+end
compose (generic function with 76 methods)

expressions are represented at expression trees

ex = compose(P, [:f, :g])

\[f \cdot g : X \to Z\]

the head of an expression is the root of the expression tree

head(ex)
:compose

the julia type of the expression

typeof(ex)
Catlab.Theories.FreeThinCategory.Hom{:compose}

the GAT type of the expression

gat_typeof(ex)
:Hom

the parameters of the GAT Type

gat_type_args(ex)
2-element Vector{GATExpr}:
+ X
+ Z

in any thin category there is at most one morphism between any pair of objects. In symbols: ex₁::Hom(X,Y) ∧ ex₂::Hom(X,Y) ⟹ ex₁ == ex₂

function thinequal(ex₁::FreeThinCategory.Hom, ex₂::FreeThinCategory.Hom)
+  dom(ex₁) == dom(ex₂) && codom(ex₁) == codom(ex₂)
+end
+
+@test thinequal(ex, compose(P, [:f,:g])⋅id(generator(P,:Z)))
Test Passed

Thinking in terms of preorders, the composite f⋅g::Hom(X,Z) is a proof that X ≤ Z in logical notation you would say f::Hom(X,Y) and g::Hom(Y,Z) ⊢ f⋅g::Hom(X,Z) given a proof that X≤Y and a proof of Y≤Z then ⋅ will create a proof of X≤Z by composing the proofs sequentially like chaining inequalities in math a key aspect of category theory is that you want to work constructively you don't want to know that there exists a composite, you want to hold onto that composite. in programming, the way that you hold onto things is putting data into data structures. While computers can access things by offset or addresses, programmers want to use names so when we prove in P that X≤Z, we name that proof by adding it as a generator

@present P₂(FreeThinCategory) begin
+  (X,Y,Z)::Ob
+  f::Hom(X,Y)
+  g::Hom(Y,Z)
+  h::Hom(X,Z)
+end
+
+ex = compose(P₂, [:f, :g])

\[f \cdot g : X \to Z\]

Now that we have a name for h, we can see that thinequal knows that f⋅g == h because according to the definition of a thin category, any two morphisms with the same domain and codomain are equal.

@test thinequal(ex, generator(P₂, :h))
Test Passed

There is an imperative interface to manipulating presentations by mutating them for this purpose

P₂′ = copy(P)
+add_generator!(P₂′, Hom(:h, P[:X], P[:Z]))
+generators(P₂′)
6-element Vector{Any}:
+ X
+ Y
+ Z
+ f: X → Y
+ g: Y → Z
+ h: X → Z

We could avoid this naming the homs situation by giving all the homs the same name however, then when you tried to write down a morphism, you wouldn't be able to refer to a specific one by name, because they are all named ≤.

@present R(FreeThinCategory) begin
+  (x,y,z)::Ob
+  (≤)::Hom(x,y)
+end
+generators(R)
4-element Vector{Any}:
+ x
+ y
+ z
+ ≤: x → y

Catlab won't let you make a presentation where the homs have the same exact name. So, this will error:

@present Q(FreeThinCategory) begin
+  (x,y,z)::Ob
+  (≤)::Hom(x,y)
+  (≤)::Hom(y,z)
+  (≤)::Hom(x,z)
+end

However, you can omit the names for homs with the following syntax, which is useful for thin categories.

@present Q(FreeThinCategory) begin
+  (x,y,z)::Ob
+  ::Hom(x,y)
+  ::Hom(y,z)
+  ::Hom(x,z)
+end

In a thin category, all the homs with the same domain and codomain are the same, so why don't we name them by their the domain and codomain and then use the property that any two homs with the same name are the same to encode the thinness. This is what the Hasse diagram representation does for us. The edges in the diagram are encoding the presentation data into a combinatorial object that we can visualize. There are many reasons to encode a logical structure into a combinatorial strucuture, one is that we generally have ways of drawing combinatorial objects that convey their saliant structure and enable visual reasoning. Another is algorithms, isomorphism between the combinatorial representations provide some of the isomorphisms between the logical structures. in this case, a graph homomorphism between Hasse Diagrams construct isomorphisms between the preorders they present. The converse is not true since there can be many Graphs that present the same preorder.

Monotone Maps

a generator is in the set of homs if it is in the list of generators

in_homs(f::FreeThinCategory.Hom{:generator}, C::FinCat) =
+  f in hom_generators(C)
in_homs (generic function with 1 method)

a composite hom is in the list set of homs if all of its components are.

in_homs(f::FreeThinCategory.Hom{:compose}, C::FinCat) =
+  all(fᵢ->in_homs(fᵢ, C), args(f))
in_homs (generic function with 2 methods)

we can check if a map is functorial, which is called monotone for preorders.

  1. make sure all the objects in the domain are sent to objects in the codomain
  2. make sure all the homs are sent to homs in the codomain
  3. check that the domains and codomainss of the homs match
function is_functorial(F::FinFunctor)
+  pₒ = map(ob_generators(dom(F))) do X
+    F(X) in ob_generators(codom(F))
+  end |> all
+
+  pₕ = map(hom_generators(dom(F))) do f
+    in_homs(F(f), codom(F))
+  end |> all
+
+  pᵩ = map(hom_generators(dom(F))) do f
+    FX = F(dom(f))
+    FY = F(codom(f))
+    Ff = F(f)
+    dom(Ff) == FX && codom(Ff) == FY
+  end |> all
+  return pₒ && pₕ && pᵩ
+end
+
+@present Q(FreeThinCategory) begin
+  (a,b,c,d)::Ob
+  ab::Hom(a,b)
+  bc::Hom(b,c)
+  cd::Hom(c,d)
+end
+generators(Q)
+
+Fₒ = Dict(:X=>:a, :Y=>:b, :Z=>:c)
+Fₕ = Dict(:f=>:ab, :g=>:bc)
+F = FinFunctor(Fₒ, Fₕ, P, Q)
+@test is_functorial(F)
+
+Fₒ = Dict(:X=>:a, :Y=>:b, :Z=>:d)
+Fₕ = Dict(:f=>:ab, :g=>[:bc, :cd])
+F = FinFunctor(Fₒ, Fₕ, P, Q)
+@test is_functorial(F)
+
+
+Fₒ = Dict(:X=>:a, :Y=>:b, :Z=>:c)
+Fₕ = Dict(:f=>:ab, :g=>[:bc, :cd])
+F = FinFunctor(Fₒ, Fₕ, P, Q)
+@test !is_functorial(F)
Test Passed

Monotone maps are functors for thin categories. One of the benefits of category theory is that we find abstractions that work in multiple domains. The abstraction of preserving the domains and codomains of morphisms is a key abstraction that we can use to define many notions in mathematics.

diff --git a/v0.16.12/generated/sketches/smc.ipynb b/v0.16.12/generated/sketches/smc.ipynb new file mode 100644 index 000000000..3a99e6412 --- /dev/null +++ b/v0.16.12/generated/sketches/smc.ipynb @@ -0,0 +1,1104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Symmetric Monoidal Categories\n", + "\n", + "\n", + "This vignette supports section 4.4.3 of Seven Sketches in Compositionality, which introduces the definition of symmetric monoidal categories (SMCs). SMCs are a core concept in applied category theory and are a workhorse of Catlab's utility in computing applications. We will discuss the definition as a GAT, see examples of working with formulas, and conversions to wiring diagrams (sometimes called string diagrams). SMCs are useful for modeling mathematical structures like programs or processes where the objects represent data or things and the morphisms represent processes that happen to those things." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "draw (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using GATlab, Catlab.Theories\n", + "using Catlab.CategoricalAlgebra\n", + "using Catlab.WiringDiagrams\n", + "using Catlab.Programs\n", + "using Catlab.Graphics\n", + "using Catlab.Graphics: Graphviz\n", + "\n", + "draw(d::WiringDiagram) = to_graphviz(d,\n", + " orientation=LeftToRight,\n", + " labels=true, label_attr=:xlabel,\n", + " node_attrs=Graphviz.Attributes(\n", + " :fontname => \"Courier\",\n", + " ),\n", + " edge_attrs=Graphviz.Attributes(\n", + " :fontname => \"Courier\",\n", + " )\n", + ")" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Definition\n", + "Let 𝒞 be a category, then a strict symmetric monoidal structure on 𝒞 has as data:\n", + "1. An object I called the monoidal unit\n", + "2. A functor ⊗: 𝒞×𝒞 → 𝒞 called the monoidal product.\n", + "3. A natural isomorphism σᵃᵇ: A⊗B → B⊗A\n", + "\n", + "It has as axioms:\n", + "1. Left identity) I⊗C = C for all objects C in 𝒞\n", + "2. Right identity) C⊗I = C for all objects C in 𝒞\n", + "3. Associativity) (A⊗B)⊗C = A⊗(B⊗C) for all objects A,B,C in 𝒞\n", + "4. Involutivity) σ(σ(A,B)) = id(A⊗B)\n", + "\n", + "In a category, you have a composition operation that captures the sequential kind of composition. For example in Set, you compose two functions f⋅g by first applying f and then applying g. In monoidal categories, you also have the parallel composition ⊗ which you can think of as representing the simultaneous exectution of two processes. We are familiar with the cartesian product in Set which takes two sets and forms the cartesian product. The cartesian product acts on functions in a similar way, f×g is the function that takes a tuple (x:dom(f),y:dom(g)) and applies them *in parallel* and returns (f(x), g(y)):(codom(f)×codom(g)). The axioms of an SMC require that these two operations work together. The Seven Sketches book suppresses an interesting axiom called the *interchange law* for brevity, but it is worth calling some attention to it. In order for the sequential and parallel composition operators to capture our intuition, we need to assert that for any functions with compatible domains we can interchange parallel and sequential operators. Formally, ((f ⊗ g) ⋅ (h ⊗ k) == (f ⋅ h) ⊗ (g ⋅ k) where (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob, f::(A → B), h::(B → C), g::(X → Y), k::(Y → Z))). This axiom says that doing f and g in parallel and then h and k in parallel is the same as doing (f then h) and (g then k) in parallel. When using SMCs to model processes, this axiom is critical to making sure that scheduling those processes is coherent.\n", + "\n", + "If the SMC is not strict, then the equations are replaced by natural isomorphisms. The choice of natural isomorphisms then becomes part of the data of the SMC. With MacLane's coherence theorem for SMCs mathematicians can think about strict SMCs and not really worry too much about the natural isomorphisms. As programmers, those chickens come home to roost and implementing an SMC requires making some choices about about how to do that strictification.\n", + "\n", + "The Catlab definitions of SMC are repeated here for convenience. Catlab allows you to implement mathematical definitions in the language of Generalized Algebraic Theories (GATs), which are a good fit for the kind of natural language definitions that mathematicians will write. Because Catlab does relatively little type inference, the GAT version of a definition can be more verbose than you would get in natural language. For example, we have to be careful about spelling out the object for an identity morphism `id(A):A → A`. The notation `@theory MonoidalCategory{Ob,Hom} <: Category{Ob,Hom}` says that a Monoidal Category is a type of Category with additional components and axioms. Catlab has only rudimentary support for Monoidal Categories that are not Symmetric Monoidal Categories. But we separate out the definitions for completeness.\n", + "```julia\n", + "@theory MonoidalCategory{Ob,Hom} <: Category{Ob,Hom} begin\n", + " otimes(A::Ob, B::Ob)::Ob\n", + " otimes(f::(A → B), g::(C → D))::((A ⊗ C) → (B ⊗ D)) ⊣\n", + " (A::Ob, B::Ob, C::Ob, D::Ob)\n", + " @op (⊗) := otimes\n", + " munit()::Ob\n", + " # Monoid axioms.\n", + " #\n", + " # The last two axioms are the naturality equations associated with the left\n", + " # and right unitors, in the strict case where they are identities.\n", + " (A ⊗ B) ⊗ C == A ⊗ (B ⊗ C) ⊣ (A::Ob, B::Ob, C::Ob)\n", + " munit() ⊗ A == A ⊣ (A::Ob)\n", + " A ⊗ munit() == A ⊣ (A::Ob)\n", + " (f ⊗ g) ⊗ h == f ⊗ (g ⊗ h) ⊣ (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob,\n", + " f::(A → X), g::(B → Y), h::(C → Z))\n", + " id(munit()) ⊗ f == f ⊣ (A::Ob, B::Ob, f::(A → B))\n", + " f ⊗ id(munit()) == f ⊣ (A::Ob, B::Ob, f::(A → B))\n", + " # Functorality axioms.\n", + " ((f ⊗ g) ⋅ (h ⊗ k) == (f ⋅ h) ⊗ (g ⋅ k)\n", + " ⊣ (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob,\n", + " f::(A → B), h::(B → C), g::(X → Y), k::(Y → Z)))\n", + " id(A ⊗ B) == id(A) ⊗ id(B) ⊣ (A::Ob, B::Ob)\n", + "end\n", + "```\n", + "To the definition of a monoidal category, we need to add the symmetry component. Catlab calls the swap morphism a braid, because that is how you visualize it in wiring diagrams, but we stick with the conventional σ unicode name. The macro `@op` tells Catlab that you want to use a unicode operator as an alias for you term constructor. If you are familiar with type theory, you might be wondering why we write the context after the terms. This is because human brains are pretty good at type inference based on notational convention and we want to mimic the English idiom \"f⋅g, where f:A→B and g:B→C are functions\".\n", + "```julia\n", + "@theory SymmetricMonoidalCategory{Ob,Hom} <: MonoidalCategory{Ob,Hom} begin\n", + " braid(A::Ob, B::Ob)::((A ⊗ B) → (B ⊗ A))\n", + " @op (σ) := braid\n", + " # Involutivity axiom.\n", + " σ(A,B) ⋅ σ(B,A) == id(A ⊗ B) ⊣ (A::Ob, B::Ob)\n", + " # Coherence axioms.\n", + " #\n", + " # Note: The last two axioms are deducible from the first two axioms together\n", + " # with the naturality equations for the left/right unitors. We record them for\n", + " # the sake of clarity and uniformity.\n", + " σ(A,B⊗C) == (σ(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ σ(A,C)) ⊣ (A::Ob, B::Ob, C::Ob)\n", + " σ(A⊗B,C) == (id(A) ⊗ σ(B,C)) ⋅ (σ(A,C) ⊗ id(B)) ⊣ (A::Ob, B::Ob, C::Ob)\n", + " σ(A,munit()) == id(A) ⊣ (A::Ob)\n", + " σ(munit(),A) == id(A) ⊣ (A::Ob)\n", + " # Naturality axiom.\n", + " (f ⊗ g) ⋅ σ(B,D) == σ(A,C) ⋅ (g ⊗ f) ⊣ (A::Ob, B::Ob, C::Ob, D::Ob,\n", + " f::(A → B), g::(C → D))\n", + "end\n", + "```" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Presentations\n", + "Just like how a preorder can be presented with Hasse Diagram or a free category can be presented by a Graph, SMCs can be presented syntactically or combinatorially. We first start with the syntactic presentation using `@present`." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "10-element Vector{Any}:\n WholeEgg\n RawEgg\n Shell\n Egg\n Pan\n Cheese\n Scramble\n crack: WholeEgg → RawEgg⊗Shell\n fry: RawEgg⊗Pan → Egg⊗Pan\n scramble: RawEgg⊗Cheese⊗Pan → Scramble⊗Pan" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "@present Cooking(FreeSymmetricMonoidalCategory) begin\n", + " (WholeEgg, RawEgg, Shell, Egg, Pan, Cheese, Scramble)::Ob\n", + " crack::Hom(WholeEgg, RawEgg⊗Shell)\n", + " fry::Hom(RawEgg⊗Pan, Egg⊗Pan)\n", + " scramble::Hom(RawEgg⊗Cheese⊗Pan, Scramble⊗Pan)\n", + "end\n", + "generators(Cooking)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "One interpretation of an SMC is that the objects are resources and the Homs are processes the domain of the Hom is the list of resources that you need to perform the process and the codomain is the list of resources that the process produces. You can think of the SMC presentation as a namespace containing all the terms in the SMC." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The objects and morphisms are accessible by name" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "fry: RawEgg⊗Pan → Egg⊗Pan", + "text/latex": "$\\mathrm{fry} : \\mathrm{RawEgg} \\otimes \\mathrm{Pan} \\to \\mathrm{Egg} \\otimes \\mathrm{Pan}$" + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "Cooking[:Egg]\n", + "Cooking[:fry]" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Then you can make complex terms using the unicode operators" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "((crack⋅(RawEggσShell))⊗id{Pan})⋅(id{Shell}⊗fry): WholeEgg⊗Pan → Shell⊗Egg⊗Pan", + "text/latex": "$\\left(\\left(\\mathrm{crack} \\cdot \\sigma_{\\mathrm{RawEgg},\\mathrm{Shell}}\\right) \\otimes \\mathrm{id}_{\\mathrm{Pan}}\\right) \\cdot \\left(\\mathrm{id}_{\\mathrm{Shell}} \\otimes \\mathrm{fry}\\right) : \\mathrm{WholeEgg} \\otimes \\mathrm{Pan} \\to \\mathrm{Shell} \\otimes \\mathrm{Egg} \\otimes \\mathrm{Pan}$" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "((Cooking[:crack]⋅σ(Cooking[:RawEgg], Cooking[:Shell])) ⊗id(Cooking[:Pan])) ⋅ (id(Cooking[:Shell])⊗Cooking[:fry])" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "Notice that Catlab will display the expected domain and codomain." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "This is called point-free notation an it is very popular in the functional programming literature where it is used to mean implicit universal quantification over the function arguments. You can think of a morphism like a function that takes an element of each domain object as input and produces an element of each codomain object as output. Not all SMCs have interpretations as functions over sets, but just like groups can be viewed as a generalization of the symmetries of geometric shapes, SMCs can be viewed as a generalization of multivariate functions." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "These presentations are very syntactic objects and expose an API for manipulating expressions." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "for g in generators(Cooking)\n", + " \"$g is a $(gat_typeof(g)) with arguments $(gat_type_args(g))\"\n", + "end" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "The `gat_typeof` function computes the algebraic type of a term by analogy to `Base.typeof` which computes the Julia type of a value." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3-element Vector{Any}:\n crack: WholeEgg → RawEgg⊗Shell\n fry: RawEgg⊗Pan → Egg⊗Pan\n scramble: RawEgg⊗Cheese⊗Pan → Scramble⊗Pan" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "homs = filter(generators(Cooking)) do g\n", + " gat_typeof(g) == :Hom\n", + "end" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "When the term is a Hom, you can get the domain and codomain of the morphism with the `dom` and `codom` functions." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3-element Vector{String}:\n \"crack: WholeEgg → otimes(RawEgg,Shell)\"\n \"fry: otimes(RawEgg,Pan) → otimes(Egg,Pan)\"\n \"scramble: otimes(RawEgg,Cheese,Pan) → otimes(Scramble,Pan)\"" + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "map(homs) do f\n", + " \"$f: $(dom(f)) → $(codom(f))\"\n", + "end" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "The terms in a `FreeSymmetricMonoidalCategory` are trees that you can navigate with `head` and `args`. The `head` of an expression is the term constructor that created it. For SMCs, this can be `:generator`, `:otimes`, `:compose`, `:id`, or `:braid`. Then `args` will give you the list of arguments to the term constructor. For terms of type Object, this will just be the list of objects that went into constructing the object. For example A⊗B⊗C will have as its head `:otimes` and as the args `[A,B,C]`. Note that the head is a symbol, but the args are objects. For a term of type `Hom`, you have the same structure, but for Homs with the head `:generator`, you get the name of the morphism as a symbol as the first argument." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "We can look at the head and args of object expressions." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(:braid, Catlab.Theories.FreeSymmetricMonoidalCategory.Ob{:generator}[Egg, Pan])" + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "headargs(x) = (head(x),args(x))\n", + "σ(Cooking[:Egg], Cooking[:Pan]) |> headargs" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "And, morphsims" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(:otimes, Catlab.Theories.FreeSymmetricMonoidalCategory.Hom{:generator}[crack, fry])" + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "headargs(Cooking[:crack]⊗Cooking[:fry])" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "The base case is generators" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(:generator, [:Egg])" + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "headargs(Cooking[:Egg])" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "And, morphisms" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(:generator, Any[:crack, WholeEgg, otimes(RawEgg,Shell)])" + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "headargs(Cooking[:crack])" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "For a more complete introspection of the expression trees, you can call `dump(ex)` which will print a very verbose representation of the entire expression tree.\n", + "\n", + "In order to compose morphisms sequentially, you have to make sure that the domains match up. In a typical SMC expression this can require padding with the identity morphism and braiding monoidal products into the right order." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(crack⊗id{Pan})⋅(id{RawEgg}⊗(ShellσPan))⋅(fry⊗id{Shell}): WholeEgg⊗Pan → Egg⊗Pan⊗Shell", + "text/latex": "$\\left(\\mathrm{crack} \\otimes \\mathrm{id}_{\\mathrm{Pan}}\\right) \\cdot \\left(\\mathrm{id}_{\\mathrm{RawEgg}} \\otimes \\sigma_{\\mathrm{Shell},\\mathrm{Pan}}\\right) \\cdot \\left(\\mathrm{fry} \\otimes \\mathrm{id}_{\\mathrm{Shell}}\\right) : \\mathrm{WholeEgg} \\otimes \\mathrm{Pan} \\to \\mathrm{Egg} \\otimes \\mathrm{Pan} \\otimes \\mathrm{Shell}$" + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "compose(Cooking[:crack]⊗id(Cooking[:Pan]),\n", + " (id(Cooking[:RawEgg])⊗ σ(Cooking[:Shell], Cooking[:Pan])),\n", + " (Cooking[:fry]⊗id(Cooking[:Shell])))" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "At some point, prefix notation is more scalable than infix notation, so you might write this as a LISP programmer would." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(crack⊗id{Pan})⋅(id{RawEgg}⊗(ShellσPan))⋅(fry⊗id{Shell}): WholeEgg⊗Pan → Egg⊗Pan⊗Shell", + "text/latex": "$\\left(\\mathrm{crack} \\otimes \\mathrm{id}_{\\mathrm{Pan}}\\right) \\cdot \\left(\\mathrm{id}_{\\mathrm{RawEgg}} \\otimes \\sigma_{\\mathrm{Shell},\\mathrm{Pan}}\\right) \\cdot \\left(\\mathrm{fry} \\otimes \\mathrm{id}_{\\mathrm{Shell}}\\right) : \\mathrm{WholeEgg} \\otimes \\mathrm{Pan} \\to \\mathrm{Egg} \\otimes \\mathrm{Pan} \\otimes \\mathrm{Shell}$" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "compose(\n", + " otimes(Cooking[:crack],\n", + " id(Cooking[:Pan])),\n", + " otimes(id(Cooking[:RawEgg]),\n", + " σ(Cooking[:Shell], Cooking[:Pan])),\n", + " otimes(Cooking[:fry],\n", + " id(Cooking[:Shell])))" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "You can view this padding as requiring explicit instructions to do noting with all the objects you aren't using. In this example, we have to tell our chef\n", + "1. Crack the egg and do nothing with the pan.\n", + "2. Do nothing with the egg and swap the shell with the pan.\n", + "3. Fry the egg and do nothing with the shell.\n", + "Obviously, this is a very tedious way to write recipes. You need to have some syntactic sugar for all this padding and swapping." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## The Program Macro\n", + "The syntactic API above is useful for manipulating terms in an arbitrary GAT and is the formal language of Catlab for representing and manipulating algebraic structures. However, when we want to work with big expressions in an SMC, the tree structure inherent to formulas is too verbose, and we want to move to a port-graph structure called `DirectedWiringDiagrams`. This gives us the benefits of combinatorial data structures like graphs with the right expressional power for representing the morphisms in an SMC." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Node(\"n0out3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"crack\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
crack
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"fry\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
fry
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"WholeEgg\", :id => \"e1\", :xlabel => \"WholeEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e2\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"RawEgg\", :id => \"e3\", :xlabel => \"RawEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Shell\", :id => \"e4\", :xlabel => \"Shell\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Egg\", :id => \"e5\", :xlabel => \"Egg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e6\", :xlabel => \"Pan\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "crack\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "WholeEgg\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "fry\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "Shell\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "RawEgg\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "Egg\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out3:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "recipe = @program Cooking (e::WholeEgg, p::Pan) begin\n", + " e′, shell = crack(e)\n", + " return shell, fry(e′, p)\n", + "end\n", + "draw(recipe)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "Catlab gives you the tools for drawing wiring diagrams. Visualization of wiring diagrams is the oldest part of Catlab and the original motivation for its development. The `@program` macro allows you to define wiring diagrams using a syntax that feels like Julia code." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The input wires are declared as *arguments* to the program, and the output wires are declared as *returns* from the function. Variables that are not consumed or by another function or returned by the program are automatically dropped." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"crack\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
crack
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"fry\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
fry
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"WholeEgg\", :id => \"e1\", :xlabel => \"WholeEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e2\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"RawEgg\", :id => \"e3\", :xlabel => \"RawEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Egg\", :id => \"e4\", :xlabel => \"Egg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e5\", :xlabel => \"Pan\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "crack\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "WholeEgg\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "fry\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "RawEgg\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "Egg\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "recipe = @program Cooking (e::WholeEgg, p::Pan) begin\n", + " e′, shell = crack(e)\n", + " return fry(e′, p)\n", + "end\n", + "draw(recipe)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "You can copy a value by using it more than once. This is visualized as a wire being split into two wires. Square brackets let you assert equality again. For material goods, you might not want to allow this merging and splitting." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Node(\"n0in3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Node(\"n0out3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"crack\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
crack
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"fry\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
fry
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"crack\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
crack
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"fry\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
fry
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"WholeEgg\", :id => \"e1\", :xlabel => \"WholeEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in3\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e2\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"WholeEgg\", :id => \"e3\", :xlabel => \"WholeEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in3\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e4\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"RawEgg\", :id => \"e5\", :xlabel => \"RawEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"RawEgg\", :id => \"e6\", :xlabel => \"RawEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Egg\", :id => \"e7\", :xlabel => \"Egg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e8\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Egg\", :id => \"e9\", :xlabel => \"Egg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e10\", :xlabel => \"Pan\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "crack\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "WholeEgg\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "crack\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n3:w\n", + "\n", + "\n", + "WholeEgg\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "fry\n", + "\n", + "\n", + "\n", + "\n", + "n0in3:e->n2:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "fry\n", + "\n", + "\n", + "\n", + "\n", + "n0in3:e->n4:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "RawEgg\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "Egg\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out3:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n4:w\n", + "\n", + "\n", + "RawEgg\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n0out2:w\n", + "\n", + "\n", + "Egg\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n0out3:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "recipe = @program Cooking (e₁::WholeEgg, e₂::WholeEgg, p::Pan) begin\n", + " e, shell = crack(e₁)\n", + " r₁, p₁ = fry(e, p)\n", + " e, shell = crack(e₂)\n", + " r₂, p₂ = fry(e, p)\n", + " return r₁, r₂, [p₁,p₂]\n", + "end\n", + "\n", + "draw(recipe)" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "You can visualize the copy and delete morphisms explicitly with the `add_junctions` function. The dots with one wire input and multiple outputs are copying values and dots with no wires out are deletions (discarding values). Not all instances of a `SymmetricMonoidalCategory` support copy and delete, for example, in manufacturing you can't duplicate a resource, and in chemistry you can't discard species. Catlab would enforce that when you tried to interpret the wiring diagram in a specific SMC." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Node(\"n0in3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Node(\"n0out3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"crack\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
crack
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"fry\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
fry
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"crack\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
crack
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"fry\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
fry
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n5\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n6\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n7\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n8\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"RawEgg\", :id => \"e5\", :xlabel => \"RawEgg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e6\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e7\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e8\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e9\", :xlabel => \"Pan\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Shell\", :id => \"e10\", :xlabel => \"Shell\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Shell\", :id => \"e11\", :xlabel => \"Shell\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Egg\", :id => \"e12\", :xlabel => \"Egg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Egg\", :id => \"e13\", :xlabel => \"Egg\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"Pan\", :id => \"e14\", :xlabel => \"Pan\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "crack\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "WholeEgg\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "crack\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n3:w\n", + "\n", + "\n", + "WholeEgg\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in3:e->n5\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "fry\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "RawEgg\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n7\n", + "\n", + "\n", + "Shell\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "Egg\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n6\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "fry\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n4:w\n", + "\n", + "\n", + "RawEgg\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n8\n", + "\n", + "\n", + "Shell\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n0out2:w\n", + "\n", + "\n", + "Egg\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n6\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "n5->n2:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "n5->n4:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n", + "\n", + "n6->n0out3:w\n", + "\n", + "\n", + "Pan\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "draw(add_junctions(recipe))" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "For more details about working with wiring diagrams in Catlab, you should look at the vignettes under wiring_diagrams which explain how wiring diagrams interact with SMC expressions and the basics of constructing and manipulation wiring diagrams." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/sketches/smc/0ee43d16.svg b/v0.16.12/generated/sketches/smc/0ee43d16.svg new file mode 100644 index 000000000..fb8f0b97d --- /dev/null +++ b/v0.16.12/generated/sketches/smc/0ee43d16.svg @@ -0,0 +1,187 @@ + + + + + + +G + + + + + + + +n1 + +crack + + + + +n0in1:e->n1:w + + +WholeEgg + + + + + + +n3 + +crack + + + + +n0in2:e->n3:w + + +WholeEgg + + + + +n5 + + + + + +n0in3:e->n5 + + +Pan + + + + + + + + + +n2 + +fry + + + + +n1:e->n2:w + + +RawEgg + + + + +n7 + + + + + +n1:e->n7 + + +Shell + + + + +n2:e->n0out1:w + + +Egg + + + + +n6 + + + + + +n2:e->n6 + + +Pan + + + + +n4 + +fry + + + + +n3:e->n4:w + + +RawEgg + + + + +n8 + + + + + +n3:e->n8 + + +Shell + + + + +n4:e->n0out2:w + + +Egg + + + + +n4:e->n6 + + +Pan + + + + +n5->n2:w + + +Pan + + + + +n5->n4:w + + +Pan + + + + +n6->n0out3:w + + +Pan + + + diff --git a/v0.16.12/generated/sketches/smc/index.html b/v0.16.12/generated/sketches/smc/index.html new file mode 100644 index 000000000..36543de86 --- /dev/null +++ b/v0.16.12/generated/sketches/smc/index.html @@ -0,0 +1,398 @@ + +Symmetric Monoidal Categories · Catlab.jl

Symmetric Monoidal Categories

This vignette supports section 4.4.3 of Seven Sketches in Compositionality, which introduces the definition of symmetric monoidal categories (SMCs). SMCs are a core concept in applied category theory and are a workhorse of Catlab's utility in computing applications. We will discuss the definition as a GAT, see examples of working with formulas, and conversions to wiring diagrams (sometimes called string diagrams). SMCs are useful for modeling mathematical structures like programs or processes where the objects represent data or things and the morphisms represent processes that happen to those things.

using GATlab, Catlab.Theories
+using Catlab.CategoricalAlgebra
+using Catlab.WiringDiagrams
+using Catlab.Programs
+using Catlab.Graphics
+using Catlab.Graphics: Graphviz
+
+draw(d::WiringDiagram) = to_graphviz(d,
+  orientation=LeftToRight,
+  labels=true, label_attr=:xlabel,
+  node_attrs=Graphviz.Attributes(
+    :fontname => "Courier",
+  ),
+  edge_attrs=Graphviz.Attributes(
+    :fontname => "Courier",
+  )
+)
draw (generic function with 1 method)

Definition

Let 𝒞 be a category, then a strict symmetric monoidal structure on 𝒞 has as data:

  1. An object I called the monoidal unit
  2. A functor ⊗: 𝒞×𝒞 → 𝒞 called the monoidal product.
  3. A natural isomorphism σᵃᵇ: A⊗B → B⊗A

It has as axioms:

  1. Left identity) I⊗C = C for all objects C in 𝒞
  2. Right identity) C⊗I = C for all objects C in 𝒞
  3. Associativity) (A⊗B)⊗C = A⊗(B⊗C) for all objects A,B,C in 𝒞
  4. Involutivity) σ(σ(A,B)) = id(A⊗B)

In a category, you have a composition operation that captures the sequential kind of composition. For example in Set, you compose two functions f⋅g by first applying f and then applying g. In monoidal categories, you also have the parallel composition ⊗ which you can think of as representing the simultaneous exectution of two processes. We are familiar with the cartesian product in Set which takes two sets and forms the cartesian product. The cartesian product acts on functions in a similar way, f×g is the function that takes a tuple (x:dom(f),y:dom(g)) and applies them in parallel and returns (f(x), g(y)):(codom(f)×codom(g)). The axioms of an SMC require that these two operations work together. The Seven Sketches book suppresses an interesting axiom called the interchange law for brevity, but it is worth calling some attention to it. In order for the sequential and parallel composition operators to capture our intuition, we need to assert that for any functions with compatible domains we can interchange parallel and sequential operators. Formally, ((f ⊗ g) ⋅ (h ⊗ k) == (f ⋅ h) ⊗ (g ⋅ k) where (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob, f::(A → B), h::(B → C), g::(X → Y), k::(Y → Z))). This axiom says that doing f and g in parallel and then h and k in parallel is the same as doing (f then h) and (g then k) in parallel. When using SMCs to model processes, this axiom is critical to making sure that scheduling those processes is coherent.

If the SMC is not strict, then the equations are replaced by natural isomorphisms. The choice of natural isomorphisms then becomes part of the data of the SMC. With MacLane's coherence theorem for SMCs mathematicians can think about strict SMCs and not really worry too much about the natural isomorphisms. As programmers, those chickens come home to roost and implementing an SMC requires making some choices about about how to do that strictification.

The Catlab definitions of SMC are repeated here for convenience. Catlab allows you to implement mathematical definitions in the language of Generalized Algebraic Theories (GATs), which are a good fit for the kind of natural language definitions that mathematicians will write. Because Catlab does relatively little type inference, the GAT version of a definition can be more verbose than you would get in natural language. For example, we have to be careful about spelling out the object for an identity morphism id(A):A → A. The notation @theory MonoidalCategory{Ob,Hom} <: Category{Ob,Hom} says that a Monoidal Category is a type of Category with additional components and axioms. Catlab has only rudimentary support for Monoidal Categories that are not Symmetric Monoidal Categories. But we separate out the definitions for completeness.

@theory MonoidalCategory{Ob,Hom} <: Category{Ob,Hom} begin
+  otimes(A::Ob, B::Ob)::Ob
+  otimes(f::(A → B), g::(C → D))::((A ⊗ C) → (B ⊗ D)) ⊣
+    (A::Ob, B::Ob, C::Ob, D::Ob)
+  @op (⊗) := otimes
+  munit()::Ob
+  # Monoid axioms.
+  #
+  # The last two axioms are the naturality equations associated with the left
+  # and right unitors, in the strict case where they are identities.
+  (A ⊗ B) ⊗ C == A ⊗ (B ⊗ C) ⊣ (A::Ob, B::Ob, C::Ob)
+  munit() ⊗ A == A ⊣ (A::Ob)
+  A ⊗ munit() == A ⊣ (A::Ob)
+  (f ⊗ g) ⊗ h == f ⊗ (g ⊗ h) ⊣ (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob,
+                                f::(A → X), g::(B → Y), h::(C → Z))
+  id(munit()) ⊗ f == f ⊣ (A::Ob, B::Ob, f::(A → B))
+  f ⊗ id(munit()) == f ⊣ (A::Ob, B::Ob, f::(A → B))
+  # Functorality axioms.
+  ((f ⊗ g) ⋅ (h ⊗ k) == (f ⋅ h) ⊗ (g ⋅ k)
+    ⊣ (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob,
+       f::(A → B), h::(B → C), g::(X → Y), k::(Y → Z)))
+  id(A ⊗ B) == id(A) ⊗ id(B) ⊣ (A::Ob, B::Ob)
+end

To the definition of a monoidal category, we need to add the symmetry component. Catlab calls the swap morphism a braid, because that is how you visualize it in wiring diagrams, but we stick with the conventional σ unicode name. The macro @op tells Catlab that you want to use a unicode operator as an alias for you term constructor. If you are familiar with type theory, you might be wondering why we write the context after the terms. This is because human brains are pretty good at type inference based on notational convention and we want to mimic the English idiom "f⋅g, where f:A→B and g:B→C are functions".

@theory SymmetricMonoidalCategory{Ob,Hom} <: MonoidalCategory{Ob,Hom} begin
+  braid(A::Ob, B::Ob)::((A ⊗ B) → (B ⊗ A))
+  @op (σ) := braid
+  # Involutivity axiom.
+  σ(A,B) ⋅ σ(B,A) == id(A ⊗ B) ⊣ (A::Ob, B::Ob)
+  # Coherence axioms.
+  #
+  # Note: The last two axioms are deducible from the first two axioms together
+  # with the naturality equations for the left/right unitors. We record them for
+  # the sake of clarity and uniformity.
+  σ(A,B⊗C) == (σ(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ σ(A,C)) ⊣ (A::Ob, B::Ob, C::Ob)
+  σ(A⊗B,C) == (id(A) ⊗ σ(B,C)) ⋅ (σ(A,C) ⊗ id(B)) ⊣ (A::Ob, B::Ob, C::Ob)
+  σ(A,munit()) == id(A) ⊣ (A::Ob)
+  σ(munit(),A) == id(A) ⊣ (A::Ob)
+  # Naturality axiom.
+  (f ⊗ g) ⋅ σ(B,D) == σ(A,C) ⋅ (g ⊗ f) ⊣ (A::Ob, B::Ob, C::Ob, D::Ob,
+                                          f::(A → B), g::(C → D))
+end

Presentations

Just like how a preorder can be presented with Hasse Diagram or a free category can be presented by a Graph, SMCs can be presented syntactically or combinatorially. We first start with the syntactic presentation using @present.

@present Cooking(FreeSymmetricMonoidalCategory) begin
+  (WholeEgg, RawEgg, Shell, Egg, Pan, Cheese, Scramble)::Ob
+  crack::Hom(WholeEgg, RawEgg⊗Shell)
+  fry::Hom(RawEgg⊗Pan, Egg⊗Pan)
+  scramble::Hom(RawEgg⊗Cheese⊗Pan, Scramble⊗Pan)
+end
+generators(Cooking)
10-element Vector{Any}:
+ WholeEgg
+ RawEgg
+ Shell
+ Egg
+ Pan
+ Cheese
+ Scramble
+ crack: WholeEgg → RawEgg⊗Shell
+ fry: RawEgg⊗Pan → Egg⊗Pan
+ scramble: RawEgg⊗Cheese⊗Pan → Scramble⊗Pan

One interpretation of an SMC is that the objects are resources and the Homs are processes the domain of the Hom is the list of resources that you need to perform the process and the codomain is the list of resources that the process produces. You can think of the SMC presentation as a namespace containing all the terms in the SMC.

The objects and morphisms are accessible by name

Cooking[:Egg]
+Cooking[:fry]

\[\mathrm{fry} : \mathrm{RawEgg} \otimes \mathrm{Pan} \to \mathrm{Egg} \otimes \mathrm{Pan}\]

Then you can make complex terms using the unicode operators

((Cooking[:crack]⋅σ(Cooking[:RawEgg], Cooking[:Shell])) ⊗id(Cooking[:Pan])) ⋅ (id(Cooking[:Shell])⊗Cooking[:fry])

\[\left(\left(\mathrm{crack} \cdot \sigma_{\mathrm{RawEgg},\mathrm{Shell}}\right) \otimes \mathrm{id}_{\mathrm{Pan}}\right) \cdot \left(\mathrm{id}_{\mathrm{Shell}} \otimes \mathrm{fry}\right) : \mathrm{WholeEgg} \otimes \mathrm{Pan} \to \mathrm{Shell} \otimes \mathrm{Egg} \otimes \mathrm{Pan}\]

Notice that Catlab will display the expected domain and codomain.

This is called point-free notation an it is very popular in the functional programming literature where it is used to mean implicit universal quantification over the function arguments. You can think of a morphism like a function that takes an element of each domain object as input and produces an element of each codomain object as output. Not all SMCs have interpretations as functions over sets, but just like groups can be viewed as a generalization of the symmetries of geometric shapes, SMCs can be viewed as a generalization of multivariate functions.

These presentations are very syntactic objects and expose an API for manipulating expressions.

for g in generators(Cooking)
+  "$g is a $(gat_typeof(g)) with arguments $(gat_type_args(g))"
+end

The gat_typeof function computes the algebraic type of a term by analogy to Base.typeof which computes the Julia type of a value.

homs = filter(generators(Cooking)) do g
+  gat_typeof(g) == :Hom
+end
3-element Vector{Any}:
+ crack: WholeEgg → RawEgg⊗Shell
+ fry: RawEgg⊗Pan → Egg⊗Pan
+ scramble: RawEgg⊗Cheese⊗Pan → Scramble⊗Pan

When the term is a Hom, you can get the domain and codomain of the morphism with the dom and codom functions.

map(homs) do f
+  "$f: $(dom(f)) → $(codom(f))"
+end
3-element Vector{String}:
+ "crack: WholeEgg → otimes(RawEgg,Shell)"
+ "fry: otimes(RawEgg,Pan) → otimes(Egg,Pan)"
+ "scramble: otimes(RawEgg,Cheese,Pan) → otimes(Scramble,Pan)"

The terms in a FreeSymmetricMonoidalCategory are trees that you can navigate with head and args. The head of an expression is the term constructor that created it. For SMCs, this can be :generator, :otimes, :compose, :id, or :braid. Then args will give you the list of arguments to the term constructor. For terms of type Object, this will just be the list of objects that went into constructing the object. For example A⊗B⊗C will have as its head :otimes and as the args [A,B,C]. Note that the head is a symbol, but the args are objects. For a term of type Hom, you have the same structure, but for Homs with the head :generator, you get the name of the morphism as a symbol as the first argument.

We can look at the head and args of object expressions.

headargs(x) = (head(x),args(x))
+σ(Cooking[:Egg], Cooking[:Pan]) |> headargs
(:braid, Catlab.Theories.FreeSymmetricMonoidalCategory.Ob{:generator}[Egg, Pan])

And, morphsims

headargs(Cooking[:crack]⊗Cooking[:fry])
(:otimes, Catlab.Theories.FreeSymmetricMonoidalCategory.Hom{:generator}[crack, fry])

The base case is generators

headargs(Cooking[:Egg])
(:generator, [:Egg])

And, morphisms

headargs(Cooking[:crack])
(:generator, Any[:crack, WholeEgg, otimes(RawEgg,Shell)])

For a more complete introspection of the expression trees, you can call dump(ex) which will print a very verbose representation of the entire expression tree.

In order to compose morphisms sequentially, you have to make sure that the domains match up. In a typical SMC expression this can require padding with the identity morphism and braiding monoidal products into the right order.

compose(Cooking[:crack]⊗id(Cooking[:Pan]),
+        (id(Cooking[:RawEgg])⊗ σ(Cooking[:Shell], Cooking[:Pan])),
+        (Cooking[:fry]⊗id(Cooking[:Shell])))

\[\left(\mathrm{crack} \otimes \mathrm{id}_{\mathrm{Pan}}\right) \cdot \left(\mathrm{id}_{\mathrm{RawEgg}} \otimes \sigma_{\mathrm{Shell},\mathrm{Pan}}\right) \cdot \left(\mathrm{fry} \otimes \mathrm{id}_{\mathrm{Shell}}\right) : \mathrm{WholeEgg} \otimes \mathrm{Pan} \to \mathrm{Egg} \otimes \mathrm{Pan} \otimes \mathrm{Shell}\]

At some point, prefix notation is more scalable than infix notation, so you might write this as a LISP programmer would.

compose(
+  otimes(Cooking[:crack],
+         id(Cooking[:Pan])),
+  otimes(id(Cooking[:RawEgg]),
+         σ(Cooking[:Shell], Cooking[:Pan])),
+  otimes(Cooking[:fry],
+         id(Cooking[:Shell])))

\[\left(\mathrm{crack} \otimes \mathrm{id}_{\mathrm{Pan}}\right) \cdot \left(\mathrm{id}_{\mathrm{RawEgg}} \otimes \sigma_{\mathrm{Shell},\mathrm{Pan}}\right) \cdot \left(\mathrm{fry} \otimes \mathrm{id}_{\mathrm{Shell}}\right) : \mathrm{WholeEgg} \otimes \mathrm{Pan} \to \mathrm{Egg} \otimes \mathrm{Pan} \otimes \mathrm{Shell}\]

You can view this padding as requiring explicit instructions to do noting with all the objects you aren't using. In this example, we have to tell our chef

  1. Crack the egg and do nothing with the pan.
  2. Do nothing with the egg and swap the shell with the pan.
  3. Fry the egg and do nothing with the shell.

Obviously, this is a very tedious way to write recipes. You need to have some syntactic sugar for all this padding and swapping.

The Program Macro

The syntactic API above is useful for manipulating terms in an arbitrary GAT and is the formal language of Catlab for representing and manipulating algebraic structures. However, when we want to work with big expressions in an SMC, the tree structure inherent to formulas is too verbose, and we want to move to a port-graph structure called DirectedWiringDiagrams. This gives us the benefits of combinatorial data structures like graphs with the right expressional power for representing the morphisms in an SMC.

recipe = @program Cooking (e::WholeEgg, p::Pan) begin
+  e′, shell = crack(e)
+  return shell, fry(e′, p)
+end
+draw(recipe)

Catlab gives you the tools for drawing wiring diagrams. Visualization of wiring diagrams is the oldest part of Catlab and the original motivation for its development. The @program macro allows you to define wiring diagrams using a syntax that feels like Julia code.

The input wires are declared as arguments to the program, and the output wires are declared as returns from the function. Variables that are not consumed or by another function or returned by the program are automatically dropped.

recipe = @program Cooking (e::WholeEgg, p::Pan) begin
+  e′, shell = crack(e)
+  return fry(e′, p)
+end
+draw(recipe)

You can copy a value by using it more than once. This is visualized as a wire being split into two wires. Square brackets let you assert equality again. For material goods, you might not want to allow this merging and splitting.

recipe = @program Cooking (e₁::WholeEgg, e₂::WholeEgg, p::Pan) begin
+  e, shell = crack(e₁)
+  r₁, p₁ = fry(e, p)
+  e, shell = crack(e₂)
+  r₂, p₂ = fry(e, p)
+  return r₁, r₂, [p₁,p₂]
+end
+
+draw(recipe)

You can visualize the copy and delete morphisms explicitly with the add_junctions function. The dots with one wire input and multiple outputs are copying values and dots with no wires out are deletions (discarding values). Not all instances of a SymmetricMonoidalCategory support copy and delete, for example, in manufacturing you can't duplicate a resource, and in chemistry you can't discard species. Catlab would enforce that when you tried to interpret the wiring diagram in a specific SMC.

draw(add_junctions(recipe))
Example block output

For more details about working with wiring diagrams in Catlab, you should look at the vignettes under wiring_diagrams which explain how wiring diagrams interact with SMC expressions and the basics of constructing and manipulation wiring diagrams.

diff --git a/v0.16.12/generated/wiring_diagrams/diagrams_and_expressions.ipynb b/v0.16.12/generated/wiring_diagrams/diagrams_and_expressions.ipynb new file mode 100644 index 000000000..0eb33b577 --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/diagrams_and_expressions.ipynb @@ -0,0 +1,614 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Wiring diagrams and syntactic expressions\n", + "\n", + "\n", + "Morphisms in a monoidal category can be represented as syntactic expressions,\n", + "such as $f \\cdot g$ and $f \\otimes g$, and also as wiring\n", + "diagrams, aka *string diagrams*. Catlab provides\n", + "facilities for transforming between these two representations." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "show_diagram (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Theories, Catlab.WiringDiagrams\n", + "using Catlab.Graphics\n", + "\n", + "function show_diagram(d::WiringDiagram)\n", + " to_graphviz(d, orientation=LeftToRight, labels=false)\n", + "end" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Expressions to diagrams\n", + "\n", + "Converting a morphism expression to a wiring diagram is conceptually and\n", + "algorithmically simple, because every expression determines a unique diagram.\n", + "\n", + "As a simple example, here is the monoidal product of two generators, $f$ and\n", + "$g$, first as an expression (displayed using LaTeX) and then as a wiring\n", + "diagram (displayed using Graphviz)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "f⊗g: A⊗B → B⊗C", + "text/latex": "$f \\otimes g : A \\otimes B \\to B \\otimes C$" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "A, B, C, D, E = Ob(FreeCartesianCategory, :A, :B, :C, :D, :E)\n", + "f = Hom(:f, A, B)\n", + "g = Hom(:g, B, C)\n", + "\n", + "expr = f ⊗ g" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e4\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(to_wiring_diagram(expr))" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Here is a monoidal product of compositions:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(f⋅g)⊗(h⋅k): A⊗C → C⊗E", + "text/latex": "$\\left(f \\cdot g\\right) \\otimes \\left(h \\cdot k\\right) : A \\otimes C \\to C \\otimes E$" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "h = Hom(:h, C, D)\n", + "k = Hom(:k, D, E)\n", + "\n", + "expr = (f ⋅ g) ⊗ (h ⋅ k)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"k\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
k
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"D\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"E\", :id => \"e6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "k\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n4:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n0out2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(to_wiring_diagram(expr))" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "## Diagrams to expressions\n", + "\n", + "Converting a wiring diagram to a syntactic expression is algorithmically more\n", + "challenging, due to the fact that a single wiring diagram generally admits\n", + "many different representations as an expression. Thus, a particular expression\n", + "must be singled out.\n", + "\n", + "To bring this out, we define a function that round-trips a morphism expression\n", + "to a wiring diagram and then back to an expression." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "roundtrip_expr (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "function roundtrip_expr(expr::FreeCartesianCategory.Hom)\n", + " d = to_wiring_diagram(expr)\n", + " to_hom_expr(FreeCartesianCategory, d)\n", + "end" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "We can recover the expression just considered above:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(f⋅g)⊗(h⋅k): A⊗C → C⊗E", + "text/latex": "$\\left(f \\cdot g\\right) \\otimes \\left(h \\cdot k\\right) : A \\otimes C \\to C \\otimes E$" + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "roundtrip_expr((f ⋅ g) ⊗ (h ⋅ k))" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "But here is a different expression that round-trips to the same thing:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(f⋅g)⊗(h⋅k): A⊗C → C⊗E", + "text/latex": "$\\left(f \\cdot g\\right) \\otimes \\left(h \\cdot k\\right) : A \\otimes C \\to C \\otimes E$" + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "roundtrip_expr((f ⊗ h) ⋅ (g ⊗ k))" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "The equality of these two expressions,\n", + "\n", + "$$\n", + "(f \\cdot g) \\otimes (h \\cdot k) = (f \\otimes h) \\cdot (g \\otimes k),\n", + "$$\n", + "\n", + "is the *interchange law* in a monoidal category. It says that composition and\n", + "monoidal products can be interchanged. As this example shows, the conversion\n", + "algorithm in Catlab favors products over composition, placing products towards\n", + "the root of the expression tree wherever possible.\n", + "Other laws can be discovered by this procedure. Since we are working in a\n", + "[cartesian monoidal\n", + "category](https://ncatlab.org/nlab/show/cartesian+monoidal+category),\n", + "operations of copying, $\\Delta_A: A \\to A \\otimes A$, and deleting,\n", + "$\\lozenge_A: A \\to I$, are available.\n", + "\n", + "Consider the operation of copying the product $A \\otimes B$." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "mcopy{A⊗B}: A⊗B → A⊗B⊗A⊗B", + "text/latex": "$\\Delta_{A \\otimes B} : A \\otimes B \\to A \\otimes B \\otimes A \\otimes B$" + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "expr = mcopy(A ⊗ B)" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Node(\"n0out3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out3\")), Catlab.Graphics.Graphviz.Node(\"n0out4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n2\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out3\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out4\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e6\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Serif\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1->n0out1:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1->n0out3:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2->n0out2:w\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2->n0out4:w\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(add_junctions!(to_wiring_diagram(expr)))" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "(mcopy{A}⊗mcopy{B})⋅(id{A}⊗(AσB)⊗id{B}): A⊗B → A⊗B⊗A⊗B", + "text/latex": "$\\left(\\Delta_{A} \\otimes \\Delta_{B}\\right) \\cdot \\left(\\mathrm{id}_{A} \\otimes \\sigma_{A,B} \\otimes \\mathrm{id}_{B}\\right) : A \\otimes B \\to A \\otimes B \\otimes A \\otimes B$" + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "roundtrip_expr(expr)" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "The equation just witnessed,\n", + "\n", + "$$\n", + "\\Delta_{A \\otimes B} = (\\Delta_A \\otimes \\Delta_B) \\cdot (1_A \\otimes \\sigma_{A,B} \\otimes 1_B),\n", + "$$\n", + "\n", + "is one of the *coherence laws* for cartesian products\n", + "([arXiv:0908.3347](https://arxiv.org/abs/0908.3347), Table 7). Another\n", + "coherence law for products is\n", + "\n", + "$$\n", + "\\lozenge_{A \\otimes B} = \\lozenge_A \\otimes \\lozenge_B.\n", + "$$" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "delete{A⊗B}: A⊗B → I", + "text/latex": "$\\lozenge_{A \\otimes B} : A \\otimes B \\to I$" + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "expr = delete(A ⊗ B)" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "delete{A}⊗delete{B}: A⊗B → I", + "text/latex": "$\\lozenge_{A} \\otimes \\lozenge_{B} : A \\otimes B \\to I$" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "roundtrip_expr(expr)" + ], + "metadata": {}, + "execution_count": 13 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/wiring_diagrams/diagrams_and_expressions/index.html b/v0.16.12/generated/wiring_diagrams/diagrams_and_expressions/index.html new file mode 100644 index 000000000..d260d0f5d --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/diagrams_and_expressions/index.html @@ -0,0 +1,244 @@ + +Wiring diagrams and syntactic expressions · Catlab.jl

Wiring diagrams and syntactic expressions

Morphisms in a monoidal category can be represented as syntactic expressions, such as $f \cdot g$ and $f \otimes g$, and also as wiring diagrams, aka string diagrams. Catlab provides facilities for transforming between these two representations.

using Catlab.Theories, Catlab.WiringDiagrams
+using Catlab.Graphics
+
+function show_diagram(d::WiringDiagram)
+  to_graphviz(d, orientation=LeftToRight, labels=false)
+end
show_diagram (generic function with 1 method)

Expressions to diagrams

Converting a morphism expression to a wiring diagram is conceptually and algorithmically simple, because every expression determines a unique diagram.

As a simple example, here is the monoidal product of two generators, $f$ and $g$, first as an expression (displayed using LaTeX) and then as a wiring diagram (displayed using Graphviz).

A, B, C, D, E = Ob(FreeCartesianCategory, :A, :B, :C, :D, :E)
+f = Hom(:f, A, B)
+g = Hom(:g, B, C)
+
+expr = f ⊗ g

\[f \otimes g : A \otimes B \to B \otimes C\]

show_diagram(to_wiring_diagram(expr))

Here is a monoidal product of compositions:

h = Hom(:h, C, D)
+k = Hom(:k, D, E)
+
+expr = (f ⋅ g) ⊗ (h ⋅ k)

\[\left(f \cdot g\right) \otimes \left(h \cdot k\right) : A \otimes C \to C \otimes E\]

show_diagram(to_wiring_diagram(expr))

Diagrams to expressions

Converting a wiring diagram to a syntactic expression is algorithmically more challenging, due to the fact that a single wiring diagram generally admits many different representations as an expression. Thus, a particular expression must be singled out.

To bring this out, we define a function that round-trips a morphism expression to a wiring diagram and then back to an expression.

function roundtrip_expr(expr::FreeCartesianCategory.Hom)
+  d = to_wiring_diagram(expr)
+  to_hom_expr(FreeCartesianCategory, d)
+end
roundtrip_expr (generic function with 1 method)

We can recover the expression just considered above:

roundtrip_expr((f ⋅ g) ⊗ (h ⋅ k))

\[\left(f \cdot g\right) \otimes \left(h \cdot k\right) : A \otimes C \to C \otimes E\]

But here is a different expression that round-trips to the same thing:

roundtrip_expr((f ⊗ h) ⋅ (g ⊗ k))

\[\left(f \cdot g\right) \otimes \left(h \cdot k\right) : A \otimes C \to C \otimes E\]

The equality of these two expressions,

\[(f \cdot g) \otimes (h \cdot k) = (f \otimes h) \cdot (g \otimes k),\]

is the interchange law in a monoidal category. It says that composition and monoidal products can be interchanged. As this example shows, the conversion algorithm in Catlab favors products over composition, placing products towards the root of the expression tree wherever possible. Other laws can be discovered by this procedure. Since we are working in a cartesian monoidal category, operations of copying, $\Delta_A: A \to A \otimes A$, and deleting, $\lozenge_A: A \to I$, are available.

Consider the operation of copying the product $A \otimes B$.

expr = mcopy(A ⊗ B)

\[\Delta_{A \otimes B} : A \otimes B \to A \otimes B \otimes A \otimes B\]

show_diagram(add_junctions!(to_wiring_diagram(expr)))
roundtrip_expr(expr)

\[\left(\Delta_{A} \otimes \Delta_{B}\right) \cdot \left(\mathrm{id}_{A} \otimes \sigma_{A,B} \otimes \mathrm{id}_{B}\right) : A \otimes B \to A \otimes B \otimes A \otimes B\]

The equation just witnessed,

\[\Delta_{A \otimes B} = (\Delta_A \otimes \Delta_B) \cdot (1_A \otimes \sigma_{A,B} \otimes 1_B),\]

is one of the coherence laws for cartesian products (arXiv:0908.3347, Table 7). Another coherence law for products is

\[\lozenge_{A \otimes B} = \lozenge_A \otimes \lozenge_B.\]

expr = delete(A ⊗ B)

\[\lozenge_{A \otimes B} : A \otimes B \to I\]

roundtrip_expr(expr)

\[\lozenge_{A} \otimes \lozenge_{B} : A \otimes B \to I\]

diff --git a/v0.16.12/generated/wiring_diagrams/wd_cset.ipynb b/v0.16.12/generated/wiring_diagrams/wd_cset.ipynb new file mode 100644 index 000000000..49d01c9bf --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/wd_cset.ipynb @@ -0,0 +1,2814 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Wiring Diagrams as Attributed C-Sets\n", + "Catlab supports many different flavors of diagrammatic syntax. These support the different combinatorial data structures that we use for representing categorical constructions. We will discuss DirectedWiringDiagrams, UndirectedWiringDiagrams, and CPortGraphs in this document." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "draw (generic function with 2 methods)" + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Theories, Catlab.CategoricalAlgebra\n", + "using Catlab.WiringDiagrams, Catlab.Programs, Catlab.Graphics\n", + "using Catlab.Graphics: Graphviz\n", + "\n", + "draw(d::WiringDiagram) = to_graphviz(d,\n", + " orientation=LeftToRight,\n", + " labels=true, label_attr=:xlabel,\n", + " node_attrs=Graphviz.Attributes(\n", + " :fontname => \"Courier\",\n", + " ),\n", + " edge_attrs=Graphviz.Attributes(\n", + " :fontname => \"Courier\",\n", + " )\n", + ")\n", + "\n", + "draw(uwd::AbstractUWD) = to_graphviz(uwd, junction_labels=:variable, box_labels=:name)" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Directed Wiring Diagrams" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "DWDs are used to represent the morphisms in a symmetric monoidal category. You can get started by presenting a `FreeSymmetricMonoidalCategory` with the `@present` macro." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "8-element Vector{Any}:\n A\n B\n C\n D\n f: A → B\n g: B → A\n h: A⊗B → C\n k: C → D⊗A" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "@present P(FreeSymmetricMonoidalCategory) begin\n", + " (A,B,C,D)::Ob\n", + " f::Hom(A,B)\n", + " g::Hom(B,A)\n", + " h::Hom(A⊗B, C)\n", + " k::Hom(C,D⊗A)\n", + "end\n", + "generators(P)" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "These presentations are very syntactic objects and expose an API for manipulating expressions." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "for g in generators(P)\n", + " \"$g is a $(gat_typeof(g)) with arguments $(gat_type_args(g))\"\n", + "end" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "The `gat_typeof` function computes the algebraic type of a term by analogy to `Base.typeof` which computes the Julia type of a value." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "4-element Vector{Any}:\n f: A → B\n g: B → A\n h: A⊗B → C\n k: C → D⊗A" + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "homs_P = filter(generators(P)) do g\n", + " gat_typeof(g) == :Hom\n", + "end" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "When the term is a Hom, you can get the domain and codomain of the morphism with the `dom` and `codom` functions." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "4-element Vector{String}:\n \"f: A → B\"\n \"g: B → A\"\n \"h: otimes(A,B) → C\"\n \"k: C → otimes(D,A)\"" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "map(homs_P) do f\n", + " \"$f: $(dom(f)) → $(codom(f))\"\n", + "end" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "cell_type": "markdown", + "source": [ + "With the presentation you can build up morphism expressions using a formula syntax." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "h⋅k: A⊗B → D⊗A", + "text/latex": "$h \\cdot k : A \\otimes B \\to D \\otimes A$" + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "P[:h]⋅P[:k]" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "This syntactic API is useful for manipulating terms in an arbitrary GAT and is the formal language of Catlab for representing and manipulating algebraic structures.\n", + "However, when we want to work with big expressions in an SMC, the tree structure inherent to formulas is too verbose, and we want to move to a port-graph structure called `DirectedWiringDiagrams`. This gives us the benefits of combinatorial data structures like graphs with the right expressional power for representing the morphisms in an SMC." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"k\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
k
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e3\", :xlabel => \"C\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"D\", :id => \"e4\", :xlabel => \"D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e5\", :xlabel => \"A\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "k\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "D\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "wd = @program P (a::A, b::B) begin\n", + " c = h(a,b)\n", + " return k(c)\n", + "end\n", + "\n", + "draw(wd)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "Catlab gives you the tools for drawing wiring diagrams. Visualization of wiring diagrams is the oldest part of Catlab and the original motivation for its development. The `@program` macro allows you to define wiring diagrams using a syntax that feels like Julia code." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"k\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
k
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e3\", :xlabel => \"C\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"D\", :id => \"e5\", :xlabel => \"D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e6\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "k\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "D\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n3:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n0out2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "wd = @program P (a::A, b::B) begin\n", + " c = h(a,b)\n", + " d,a₁ = k(c)\n", + " return d, f(a₁)\n", + "end\n", + "draw(wd)" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "The input wires are declared as *arguments* to the program, and the output wires are declared as *returns* from the function. Variables that are not consumed or by another function or returned by the program are automatically dropped." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"k\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
k
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e3\", :xlabel => \"C\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e4\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "k\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n3:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "wd = @program P (a::A, b::B) begin\n", + " c = h(a,b)\n", + " d,a₁ = k(c)\n", + " return f(a₁)\n", + "end\n", + "draw(wd)" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "cell_type": "markdown", + "source": [ + "You can copy a value by using it more than once. This is visualized as a wire being split into two wires." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e1\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e3\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e4\", :xlabel => \"C\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "wd = @program P (b::B) begin\n", + " h(g(b),b)\n", + "end\n", + "draw(wd)" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "cell_type": "markdown", + "source": [ + "You can visualize the copy and delete morphisms explicitly with the `add_junctions` function. The dots with one wire input and multiple outputs are copying values and dots with no wires out are deletions (discarding values). Not all instances of a `SymmetricMonoidalCategory` support copy and delete, for example, in manufacturing you can't duplicate a resource, and in chemistry you can't discard species. Catlab would enforce that when you tried to interpret the wiring diagram in a specific SMC." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"k\", :fillcolor => \"white\", :id => \"n3\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
k
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n4\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n5\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.05\", :id => \"n6\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.05\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e1\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out2\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e3\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e4\", :xlabel => \"C\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e5\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in2\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e6\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"D\", :id => \"e7\", :xlabel => \"D\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e8\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n5\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "k\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n3:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n4:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3:e->n6\n", + "\n", + "\n", + "D\n", + "\n", + "\n", + "\n", + "\n", + "n4:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n5->n1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n5->n2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "wd = @program P (b::B) begin\n", + " c = h(g(b),b)\n", + " d, a₁ = k(c)\n", + " return f(a₁)\n", + "end\n", + "draw(add_junctions(wd))" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "cell_type": "markdown", + "source": [ + "For more details about working with wiring diagrams in Catlab, you should look at the other vignettes in this section which explain how wiring diagrams interact with SMC expressions and the basics of constructing and manipulation wiring diagrams." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Diagrams as C-Sets" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The underlying data of a wiring diagram is combinatorial. That means we can represent it as a C-Set" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagramACSet{Any, Any, Any, DataType} {Box:4, InPort:5, OutPort:5, OuterInPort:1, OuterOutPort:1, Wire:3, InWire:2, OutWire:1, PassWire:0, PortValue:0, WireValue:0, BoxValue:0, BoxType:0}\n┌─────┬───────┬─────────────┐\n│\u001b[1m Box │\u001b[1m value │\u001b[1m box_type │\n├─────┼───────┼─────────────┤\n│\u001b[1m 1 │ g │ Box{Symbol} │\n│\u001b[1m 2 │ h │ Box{Symbol} │\n│\u001b[1m 3 │ k │ Box{Symbol} │\n│\u001b[1m 4 │ f │ Box{Symbol} │\n└─────┴───────┴─────────────┘\n┌────────┬─────────────┬──────────────┐\n│\u001b[1m InPort │\u001b[1m in_port_box │\u001b[1m in_port_type │\n├────────┼─────────────┼──────────────┤\n│\u001b[1m 1 │ 1 │ B │\n│\u001b[1m 2 │ 2 │ A │\n│\u001b[1m 3 │ 2 │ B │\n│\u001b[1m 4 │ 3 │ C │\n│\u001b[1m 5 │ 4 │ A │\n└────────┴─────────────┴──────────────┘\n┌─────────┬──────────────┬───────────────┐\n│\u001b[1m OutPort │\u001b[1m out_port_box │\u001b[1m out_port_type │\n├─────────┼──────────────┼───────────────┤\n│\u001b[1m 1 │ 1 │ A │\n│\u001b[1m 2 │ 2 │ C │\n│\u001b[1m 3 │ 3 │ D │\n│\u001b[1m 4 │ 3 │ A │\n│\u001b[1m 5 │ 4 │ B │\n└─────────┴──────────────┴───────────────┘\n┌─────────────┬────────────────────┐\n│\u001b[1m OuterInPort │\u001b[1m outer_in_port_type │\n├─────────────┼────────────────────┤\n│\u001b[1m 1 │ B │\n└─────────────┴────────────────────┘\n┌──────────────┬─────────────────────┐\n│\u001b[1m OuterOutPort │\u001b[1m outer_out_port_type │\n├──────────────┼─────────────────────┤\n│\u001b[1m 1 │ B │\n└──────────────┴─────────────────────┘\n┌──────┬─────┬─────┬────────────┐\n│\u001b[1m Wire │\u001b[1m src │\u001b[1m tgt │\u001b[1m wire_value │\n├──────┼─────┼─────┼────────────┤\n│\u001b[1m 1 │ 4 │ 5 │ nothing │\n│\u001b[1m 2 │ 1 │ 2 │ nothing │\n│\u001b[1m 3 │ 2 │ 4 │ nothing │\n└──────┴─────┴─────┴────────────┘\n┌────────┬────────┬────────┬───────────────┐\n│\u001b[1m InWire │\u001b[1m in_src │\u001b[1m in_tgt │\u001b[1m in_wire_value │\n├────────┼────────┼────────┼───────────────┤\n│\u001b[1m 1 │ 1 │ 1 │ nothing │\n│\u001b[1m 2 │ 1 │ 3 │ nothing │\n└────────┴────────┴────────┴───────────────┘\n┌─────────┬─────────┬─────────┬────────────────┐\n│\u001b[1m OutWire │\u001b[1m out_src │\u001b[1m out_tgt │\u001b[1m out_wire_value │\n├─────────┼─────────┼─────────┼────────────────┤\n│\u001b[1m 1 │ 5 │ 1 │ nothing │\n└─────────┴─────────┴─────────┴────────────────┘\n", + "text/html": [ + "
\n", + "Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagramACSet{Any, Any, Any, DataType} {Box:4, InPort:5, OutPort:5, OuterInPort:1, OuterOutPort:1, Wire:3, InWire:2, OutWire:1, PassWire:0, PortValue:0, WireValue:0, BoxValue:0, BoxType:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Boxvaluebox_type
1gBox{Symbol}
2hBox{Symbol}
3kBox{Symbol}
4fBox{Symbol}
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
InPortin_port_boxin_port_type
11B
22A
32B
43C
54A
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OutPortout_port_boxout_port_type
11A
22C
33D
43A
54B
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OuterInPortouter_in_port_type
1B
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OuterOutPortouter_out_port_type
1B
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Wiresrctgtwire_value
145nothing
212nothing
324nothing
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
InWirein_srcin_tgtin_wire_value
111nothing
213nothing
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OutWireout_srcout_tgtout_wire_value
151nothing
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "wd.diagram" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "Ok, there is a lot in there. The columns with integer entries are the combinatorial data encoding the connectivity of the wiring diagram. The columns with Symbols in them are encoding the labels for the diagram, the `value` of a box is the content of the box. Ports have types and wires have values. When we define the wiring diagram with the `@program` macro, we get a diagram that has labels and types, but no values. These values are initialized to nothing, but could be filled with values to be carried down the wires in an application." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The schema of for wiring diagrams is called `SchAttributedWiringDiagrams` and is a little overwhelming, so we can explore how to build it up with C-Set schema inheritance." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Box\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"InPort\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OutPort\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterInPort\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterOutPort\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Wire\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"InWire\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OutWire\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"PassWire\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"point\", :xlabel => \"PortValue\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"outer_in_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"outer_out_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n12\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"value\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n13\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"box_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"wire_value\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_wire_value\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_wire_value\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n11\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"pass_wire_value\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "Box\n", + "\n", + "\n", + "\n", + "n12\n", + "\n", + "BoxValue\n", + "\n", + "\n", + "\n", + "n1->n12\n", + "\n", + "\n", + "value\n", + "\n", + "\n", + "\n", + "n13\n", + "\n", + "BoxType\n", + "\n", + "\n", + "\n", + "n1->n13\n", + "\n", + "\n", + "box_type\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "InPort\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "in_port_box\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "PortValue\n", + "\n", + "\n", + "\n", + "n2->n10\n", + "\n", + "\n", + "in_port_type\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "OutPort\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "out_port_box\n", + "\n", + "\n", + "\n", + "n3->n10\n", + "\n", + "\n", + "out_port_type\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "OuterInPort\n", + "\n", + "\n", + "\n", + "n4->n10\n", + "\n", + "\n", + "outer_in_port_type\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "OuterOutPort\n", + "\n", + "\n", + "\n", + "n5->n10\n", + "\n", + "\n", + "outer_out_port_type\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "Wire\n", + "\n", + "\n", + "\n", + "n6->n2\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n", + "n6->n3\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n11\n", + "\n", + "WireValue\n", + "\n", + "\n", + "\n", + "n6->n11\n", + "\n", + "\n", + "wire_value\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "InWire\n", + "\n", + "\n", + "\n", + "n7->n2\n", + "\n", + "\n", + "in_tgt\n", + "\n", + "\n", + "\n", + "n7->n4\n", + "\n", + "\n", + "in_src\n", + "\n", + "\n", + "\n", + "n7->n11\n", + "\n", + "\n", + "in_wire_value\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "OutWire\n", + "\n", + "\n", + "\n", + "n8->n3\n", + "\n", + "\n", + "out_src\n", + "\n", + "\n", + "\n", + "n8->n5\n", + "\n", + "\n", + "out_tgt\n", + "\n", + "\n", + "\n", + "n8->n11\n", + "\n", + "\n", + "out_wire_value\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "PassWire\n", + "\n", + "\n", + "\n", + "n9->n4\n", + "\n", + "\n", + "pass_src\n", + "\n", + "\n", + "\n", + "n9->n5\n", + "\n", + "\n", + "pass_tgt\n", + "\n", + "\n", + "\n", + "n9->n11\n", + "\n", + "\n", + "pass_wire_value\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(SchAttributedWiringDiagram)" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "From the file Catlab/src/WiringDiagrams/Directed.jl\n", + "```julia\n", + "@present SchWiringDiagram(FreeSchema) begin\n", + " Box::Ob\n", + " (InPort, OutPort, OuterInPort, OuterOutPort)::Ob\n", + " (Wire, InWire, OutWire, PassWire)::Ob" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + " src::Hom(Wire, OutPort)\n", + " tgt::Hom(Wire, InPort)\n", + " in_src::Hom(InWire, OuterInPort)\n", + " in_tgt::Hom(InWire, InPort)\n", + " out_src::Hom(OutWire, OutPort)\n", + " out_tgt::Hom(OutWire, OuterOutPort)\n", + " pass_src::Hom(PassWire, OuterInPort)\n", + " pass_tgt::Hom(PassWire, OuterOutPort)" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + " in_port_box::Hom(InPort, Box)\n", + " out_port_box::Hom(OutPort, Box)\n", + "end" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "@abstract_acset_type AbstractWiringDiagram <: AbstractGraph" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "@present SchTypedWiringDiagram <: SchWiringDiagram begin\n", + " PortValue::AttrType\n", + " in_port_type::Attr(InPort, PortValue)\n", + " out_port_type::Attr(OutPort, PortValue)\n", + " outer_in_port_type::Attr(OuterInPort, PortValue)\n", + " outer_out_port_type::Attr(OuterOutPort, PortValue)\n", + "end" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "@present SchAttributedWiringDiagram <: SchTypedWiringDiagram begin\n", + " WireValue::AttrType\n", + " BoxValue::AttrType\n", + " BoxType::AttrType" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + " value::Attr(Box, BoxValue)\n", + " box_type::Attr(Box, BoxType)\n", + " wire_value::Attr(Wire, WireValue)\n", + " in_wire_value::Attr(InWire, WireValue)\n", + " out_wire_value::Attr(OutWire, WireValue)\n", + " pass_wire_value::Attr(PassWire, WireValue)\n", + "end\n", + "```" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The bare minimum diagram language is:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Box\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"InPort\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OutPort\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterInPort\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterOutPort\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Wire\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"InWire\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OutWire\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"PassWire\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"pass_src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"pass_tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_port_box\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_port_box\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "Box\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "InPort\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "in_port_box\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "OutPort\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "out_port_box\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "OuterInPort\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "OuterOutPort\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "Wire\n", + "\n", + "\n", + "\n", + "n6->n2\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n", + "n6->n3\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "InWire\n", + "\n", + "\n", + "\n", + "n7->n2\n", + "\n", + "\n", + "in_tgt\n", + "\n", + "\n", + "\n", + "n7->n4\n", + "\n", + "\n", + "in_src\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "OutWire\n", + "\n", + "\n", + "\n", + "n8->n3\n", + "\n", + "\n", + "out_src\n", + "\n", + "\n", + "\n", + "n8->n5\n", + "\n", + "\n", + "out_tgt\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "PassWire\n", + "\n", + "\n", + "\n", + "n9->n4\n", + "\n", + "\n", + "pass_src\n", + "\n", + "\n", + "\n", + "n9->n5\n", + "\n", + "\n", + "pass_tgt\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(SchWiringDiagram)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "cell_type": "markdown", + "source": [ + "And then you can add back in the types." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Box\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"InPort\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OutPort\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterInPort\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterOutPort\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Wire\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"InWire\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OutWire\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"PassWire\")), Catlab.Graphics.Graphviz.Node(\"n10\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:shape => \"point\", :xlabel => \"PortValue\")) … Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"pass_src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"pass_tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_port_box\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_port_box\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"in_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"out_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"outer_in_port_type\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n10\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"outer_out_port_type\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "Box\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "InPort\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "in_port_box\n", + "\n", + "\n", + "\n", + "n10\n", + "\n", + "PortValue\n", + "\n", + "\n", + "\n", + "n2->n10\n", + "\n", + "\n", + "in_port_type\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "OutPort\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "out_port_box\n", + "\n", + "\n", + "\n", + "n3->n10\n", + "\n", + "\n", + "out_port_type\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "OuterInPort\n", + "\n", + "\n", + "\n", + "n4->n10\n", + "\n", + "\n", + "outer_in_port_type\n", + "\n", + "\n", + "\n", + "n5\n", + "\n", + "OuterOutPort\n", + "\n", + "\n", + "\n", + "n5->n10\n", + "\n", + "\n", + "outer_out_port_type\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "Wire\n", + "\n", + "\n", + "\n", + "n6->n2\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n", + "n6->n3\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "InWire\n", + "\n", + "\n", + "\n", + "n7->n2\n", + "\n", + "\n", + "in_tgt\n", + "\n", + "\n", + "\n", + "n7->n4\n", + "\n", + "\n", + "in_src\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "OutWire\n", + "\n", + "\n", + "\n", + "n8->n3\n", + "\n", + "\n", + "out_src\n", + "\n", + "\n", + "\n", + "n8->n5\n", + "\n", + "\n", + "out_tgt\n", + "\n", + "\n", + "\n", + "n9\n", + "\n", + "PassWire\n", + "\n", + "\n", + "\n", + "n9->n4\n", + "\n", + "\n", + "pass_src\n", + "\n", + "\n", + "\n", + "n9->n5\n", + "\n", + "\n", + "pass_tgt\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(SchTypedWiringDiagram)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "cell_type": "markdown", + "source": [ + "Layout is hard, so if you want to understand the `SchAttributedWiringDiagrams`, you should do the layout by hand as an exercise." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "We can create our own version of the theory of DWDs to see how it works:" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Presentation{Catlab.Theories.ThSchema.Meta.T, Symbol}(Catlab.Theories.FreeSchema, (Ob = Catlab.Theories.FreeSchema.Ob{:generator}[Box, InPort, OutPort, OuterInPort, OuterOutPort, Wire, InWire, OutWire, PassWire], Hom = Catlab.Theories.FreeSchema.Hom{:generator}[src, tgt, in_src, in_tgt, out_src, out_tgt, pass_src, pass_tgt, in_port_box, out_port_box], AttrType = Catlab.Theories.FreeSchema.AttrType{:generator}[], Attr = Catlab.Theories.FreeSchema.Attr{:generator}[]), Dict(:InPort => (:Ob => 2), :InWire => (:Ob => 7), :in_port_box => (:Hom => 9), :Box => (:Ob => 1), :OuterOutPort => (:Ob => 5), :in_src => (:Hom => 3), :in_tgt => (:Hom => 4), :src => (:Hom => 1), :OuterInPort => (:Ob => 4), :out_port_box => (:Hom => 10)…), Pair[])" + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "@present MySchWiringDiagram(FreeSchema) begin\n", + " Box::Ob\n", + " (InPort, OutPort, OuterInPort, OuterOutPort)::Ob\n", + " (Wire, InWire, OutWire, PassWire)::Ob\n", + "\n", + " src::Hom(Wire, OutPort)\n", + " tgt::Hom(Wire, InPort)\n", + " in_src::Hom(InWire, OuterInPort)\n", + " in_tgt::Hom(InWire, InPort)\n", + " out_src::Hom(OutWire, OutPort)\n", + " out_tgt::Hom(OutWire, OuterOutPort)\n", + " pass_src::Hom(PassWire, OuterInPort)\n", + " pass_tgt::Hom(PassWire, OuterOutPort)\n", + "\n", + " in_port_box::Hom(InPort, Box)\n", + " out_port_box::Hom(OutPort, Box)\n", + "end" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "cell_type": "markdown", + "source": [ + "If your application of wiring diagrams needs to attach numeric or textual information to the boxes of a wiring diagram, you would extend the `SchWiringDiagram` with the attributes that you need. That will give you a custom data structure that has those fields. One of the goals of Catlab is to make it so much easier to generate custom data structures that interoperate, that you don't need to create generic structures that can be used for many purposes. Just snap your fingers and create a new structure perfectly tailored to your needs, when your needs change, snap again to get a new version of that structure." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The `@acset_type` macro does the hard work of generating the data structure and accessors and mutators for you. The form of this call is `@acset_type NewStructName(Schema, index=[morphisms in Schema]) <: Supertype`. You should index any morphism where you need to use `incident` frequently. For wiring diagrams you will often want to know what all the wires that are incident to a port." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Main.var\"##257\".MyWiringDiagramACSet" + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "@acset_type MyWiringDiagramACSet(MySchWiringDiagram,\n", + " index=[:src, :tgt, :in_src, :in_tgt, :out_src, :out_tgt, :pass_src, :pass_tgt]) <: WiringDiagrams.DirectedWiringDiagrams.AbstractWiringDiagram" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "We get the `@acset` macro from Catlab and can create DWDs by hand. It is very tedious, which is why the `@program` macro exists!" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Main.var\"##257\".MyWiringDiagramACSet {Box:3, InPort:6, OutPort:3, OuterInPort:0, OuterOutPort:0, Wire:3, InWire:0, OutWire:0, PassWire:0}\n┌────────┬─────────────┐\n│\u001b[1m InPort │\u001b[1m in_port_box │\n├────────┼─────────────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 1 │\n│\u001b[1m 3 │ 2 │\n│\u001b[1m 4 │ 2 │\n│\u001b[1m 5 │ 3 │\n│\u001b[1m 6 │ 3 │\n└────────┴─────────────┘\n┌─────────┬──────────────┐\n│\u001b[1m OutPort │\u001b[1m out_port_box │\n├─────────┼──────────────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 2 │\n│\u001b[1m 3 │ 3 │\n└─────────┴──────────────┘\n┌──────┬─────┬─────┐\n│\u001b[1m Wire │\u001b[1m src │\u001b[1m tgt │\n├──────┼─────┼─────┤\n│\u001b[1m 1 │ 1 │ 3 │\n│\u001b[1m 2 │ 2 │ 4 │\n│\u001b[1m 3 │ 3 │ 5 │\n└──────┴─────┴─────┘\n", + "text/html": [ + "
\n", + "Main.var\"##257\".MyWiringDiagramACSet {Box:3, InPort:6, OutPort:3, OuterInPort:0, OuterOutPort:0, Wire:3, InWire:0, OutWire:0, PassWire:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
InPortin_port_box
11
21
32
42
53
63
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OutPortout_port_box
11
22
33
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Wiresrctgt
113
224
335
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "md = @acset MyWiringDiagramACSet begin\n", + " Box = 3\n", + " InPort = 6\n", + " OutPort = 3\n", + " Wire = 3\n", + " src = [1,2,3]\n", + " tgt = [3,4,5]\n", + " in_port_box = [1,1,2,2,3,3]\n", + " out_port_box = [1,2,3]\n", + "end" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "cell_type": "markdown", + "source": [ + "## Undirected Wiring Diagrams\n", + "A much simpler structure than DWDs are known as undirected wiring diagrams. They are called undirected because ports boxes have one set of ports that aren't divided into inputs and outputs, and the wires are undirected. Wires connect junctions to ports (which live on boxes)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Box\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Port\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"OuterPort\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Junction\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"box\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"junction\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"outer_junction\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "Box\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "Port\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "box\n", + "\n", + "\n", + "\n", + "n4\n", + "\n", + "Junction\n", + "\n", + "\n", + "\n", + "n2->n4\n", + "\n", + "\n", + "junction\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "OuterPort\n", + "\n", + "\n", + "\n", + "n3->n4\n", + "\n", + "\n", + "outer_junction\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(SchUWD)" + ], + "metadata": {}, + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "These UWDs are combinatorial syntax for relations. The junctions are variables and the boxes are the relations. A relation R ⊆ X × Y has two ports one for the value of X and one for the value of Y. The expression R(x:X, y:Y) says to connect the X port of R to the junction for the variable x, and the Y port of R to the y variable junction. If two ports are attached to the same junction, then you have a constraint that those values must be equal. The outer ports are the components of the final relation. For example the following UWD encodes the relation {(x,y,z) | R(x,y) and S(y,z) for all x∈X, y∈Y, z∈Z}." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Programs.RelationalPrograms.UntypedUnnamedRelationDiagram{Symbol, Symbol} {Box:2, Port:4, OuterPort:3, Junction:3, Name:0, VarName:0}\n┌─────┬──────┐\n│\u001b[1m Box │\u001b[1m name │\n├─────┼──────┤\n│\u001b[1m 1 │ R │\n│\u001b[1m 2 │ S │\n└─────┴──────┘\n┌──────┬─────┬──────────┐\n│\u001b[1m Port │\u001b[1m box │\u001b[1m junction │\n├──────┼─────┼──────────┤\n│\u001b[1m 1 │ 1 │ 1 │\n│\u001b[1m 2 │ 1 │ 2 │\n│\u001b[1m 3 │ 2 │ 2 │\n│\u001b[1m 4 │ 2 │ 3 │\n└──────┴─────┴──────────┘\n┌───────────┬────────────────┐\n│\u001b[1m OuterPort │\u001b[1m outer_junction │\n├───────────┼────────────────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 2 │\n│\u001b[1m 3 │ 3 │\n└───────────┴────────────────┘\n┌──────────┬──────────┐\n│\u001b[1m Junction │\u001b[1m variable │\n├──────────┼──────────┤\n│\u001b[1m 1 │ x │\n│\u001b[1m 2 │ y │\n│\u001b[1m 3 │ z │\n└──────────┴──────────┘\n", + "text/html": [ + "
\n", + "Catlab.Programs.RelationalPrograms.UntypedUnnamedRelationDiagram{Symbol, Symbol} {Box:2, Port:4, OuterPort:3, Junction:3, Name:0, VarName:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Boxname
1R
2S
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Portboxjunction
111
212
322
423
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OuterPortouter_junction
11
22
33
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Junctionvariable
1x
2y
3z
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 20 + } + ], + "cell_type": "code", + "source": [ + "uwd = @relation (x, y, z) begin\n", + " R(x,y)\n", + " S(y,z)\n", + "end" + ], + "metadata": {}, + "execution_count": 20 + }, + { + "cell_type": "markdown", + "source": [ + "These UWDs are drawn with circular boxes and undirected wires. Note that since all wires go from junction to port, they are not *symmetric* wires." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\", :label => \"R\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\", :label => \"S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer1\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer2\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer3\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"x\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction2\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"y\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"z\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "R\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "x\n", + "\n", + "\n", + "\n", + "n1--n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "y\n", + "\n", + "\n", + "\n", + "n1--n7\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "S\n", + "\n", + "\n", + "\n", + "n2--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "z\n", + "\n", + "\n", + "\n", + "n2--n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n3--n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4--n7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5--n8\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ], + "cell_type": "code", + "source": [ + "draw(uwd)" + ], + "metadata": {}, + "execution_count": 21 + }, + { + "cell_type": "markdown", + "source": [ + "By adding more relations we can get bigger relations." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Programs.RelationalPrograms.UntypedUnnamedRelationDiagram{Symbol, Symbol} {Box:3, Port:7, OuterPort:2, Junction:3, Name:0, VarName:0}\n┌─────┬──────┐\n│\u001b[1m Box │\u001b[1m name │\n├─────┼──────┤\n│\u001b[1m 1 │ R │\n│\u001b[1m 2 │ S │\n│\u001b[1m 3 │ T │\n└─────┴──────┘\n┌──────┬─────┬──────────┐\n│\u001b[1m Port │\u001b[1m box │\u001b[1m junction │\n├──────┼─────┼──────────┤\n│\u001b[1m 1 │ 1 │ 1 │\n│\u001b[1m 2 │ 1 │ 3 │\n│\u001b[1m 3 │ 2 │ 3 │\n│\u001b[1m 4 │ 2 │ 2 │\n│\u001b[1m 5 │ 3 │ 1 │\n│\u001b[1m 6 │ 3 │ 2 │\n│\u001b[1m 7 │ 3 │ 3 │\n└──────┴─────┴──────────┘\n┌───────────┬────────────────┐\n│\u001b[1m OuterPort │\u001b[1m outer_junction │\n├───────────┼────────────────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 2 │\n└───────────┴────────────────┘\n┌──────────┬──────────┐\n│\u001b[1m Junction │\u001b[1m variable │\n├──────────┼──────────┤\n│\u001b[1m 1 │ x │\n│\u001b[1m 2 │ z │\n│\u001b[1m 3 │ y │\n└──────────┴──────────┘\n", + "text/html": [ + "
\n", + "Catlab.Programs.RelationalPrograms.UntypedUnnamedRelationDiagram{Symbol, Symbol} {Box:3, Port:7, OuterPort:2, Junction:3, Name:0, VarName:0}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Boxname
1R
2S
3T
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Portboxjunction
111
213
323
422
531
632
733
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OuterPortouter_junction
11
22
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Junctionvariable
1x
2z
3y
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 22 + } + ], + "cell_type": "code", + "source": [ + "uwd₂ = @relation (x, z) begin\n", + " R(x,y)\n", + " S(y,z)\n", + " T(x,z,y)\n", + "end" + ], + "metadata": {}, + "execution_count": 22 + }, + { + "cell_type": "markdown", + "source": [ + "Not all of the junctions have to be exposed to the outside world. Note that there is no distinction between arguments and return values in the relation macro. This is because relations are inherently undirected, unlike functions." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", false, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\", :label => \"R\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\", :label => \"S\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box3\", :label => \"T\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer1\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:height => \"0\", :id => \"outer2\", :label => \"\", :margin => \"0\", :shape => \"none\", :style => \"invis\", :width => \"0\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction1\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"x\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction2\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"z\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"junction\", :fillcolor => \"black\", :height => \"0.075\", :id => \"junction3\", :label => \"\", :shape => \"circle\", :style => \"filled\", :width => \"0.075\", :xlabel => \"y\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n4\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n6\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n5\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n7\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}()), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n8\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "R\n", + "\n", + "\n", + "\n", + "\n", + "n6\n", + "\n", + "x\n", + "\n", + "\n", + "\n", + "n1--n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n8\n", + "\n", + "y\n", + "\n", + "\n", + "\n", + "n1--n8\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "S\n", + "\n", + "\n", + "\n", + "\n", + "n7\n", + "\n", + "z\n", + "\n", + "\n", + "\n", + "n2--n7\n", + "\n", + "\n", + "\n", + "\n", + "n2--n8\n", + "\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "T\n", + "\n", + "\n", + "\n", + "n3--n6\n", + "\n", + "\n", + "\n", + "\n", + "n3--n7\n", + "\n", + "\n", + "\n", + "\n", + "n3--n8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n4--n6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n5--n7\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ], + "cell_type": "code", + "source": [ + "draw(uwd₂)" + ], + "metadata": {}, + "execution_count": 23 + }, + { + "cell_type": "markdown", + "source": [ + "## Circular Port Graphs\n", + "CPGs are the natural data structure for representing process of interconnected systems that share information along wires, but send different information to their different neighbors." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Box\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Port\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"Wire\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"src\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"tgt\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:label => \"box\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:margin => \"0\", :shape => \"ellipse\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "Box\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "Port\n", + "\n", + "\n", + "\n", + "n2->n1\n", + "\n", + "\n", + "box\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "Wire\n", + "\n", + "\n", + "\n", + "n3->n2\n", + "\n", + "\n", + "src\n", + "\n", + "\n", + "\n", + "n3->n2\n", + "\n", + "\n", + "tgt\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 24 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(SchCPortGraph)" + ], + "metadata": {}, + "execution_count": 24 + }, + { + "cell_type": "markdown", + "source": [ + "They are also a kind of CSet, so we can use the `@acset` macro to construct them." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "CPortGraph {Box:3, Port:6, Wire:5}\n┌──────┬─────┐\n│\u001b[1m Port │\u001b[1m box │\n├──────┼─────┤\n│\u001b[1m 1 │ 1 │\n│\u001b[1m 2 │ 1 │\n│\u001b[1m 3 │ 2 │\n│\u001b[1m 4 │ 2 │\n│\u001b[1m 5 │ 3 │\n│\u001b[1m 6 │ 3 │\n└──────┴─────┘\n┌──────┬─────┬─────┐\n│\u001b[1m Wire │\u001b[1m src │\u001b[1m tgt │\n├──────┼─────┼─────┤\n│\u001b[1m 1 │ 1 │ 3 │\n│\u001b[1m 2 │ 2 │ 4 │\n│\u001b[1m 3 │ 5 │ 2 │\n│\u001b[1m 4 │ 2 │ 4 │\n│\u001b[1m 5 │ 6 │ 1 │\n└──────┴─────┴─────┘\n", + "text/html": [ + "
\n", + "CPortGraph {Box:3, Port:6, Wire:5}\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Portbox
11
21
32
42
53
63
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Wiresrctgt
113
224
352
424
561
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 25 + } + ], + "cell_type": "code", + "source": [ + "cpg = @acset CPortGraph begin\n", + " Box = 3\n", + " Port = 6\n", + " Wire = 5\n", + "\n", + " box = [1,1,2,2,3,3]\n", + " src = [1,2,5,2,6]\n", + " tgt = [3,4,2,4,1]\n", + "end" + ], + "metadata": {}, + "execution_count": 25 + }, + { + "cell_type": "markdown", + "source": [ + "the layout for CPGs is not great with graphviz." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"neato\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box1\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box2\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"box3\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:headlabel => \"1\", :id => \"edge1\", :taillabel => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:headlabel => \"2\", :id => \"edge2\", :taillabel => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:headlabel => \"2\", :id => \"edge3\", :taillabel => \"1\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:headlabel => \"2\", :id => \"edge4\", :taillabel => \"2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n3\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:headlabel => \"1\", :id => \"edge5\", :taillabel => \"2\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :nodesep => \"2\", :ranksep => \"2\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :shape => \"ellipse\", :margin => \"0.05,0.025\", :width => \"0.5\", :height => \"0.5\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :len => \"0.5\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "n1\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "n2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "1\n", + "1\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "2\n", + "2\n", + "\n", + "\n", + "\n", + "n1->n2\n", + "\n", + "\n", + "2\n", + "2\n", + "\n", + "\n", + "\n", + "n3\n", + "\n", + "n3\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "2\n", + "1\n", + "\n", + "\n", + "\n", + "n3->n1\n", + "\n", + "\n", + "1\n", + "2\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 26 + } + ], + "cell_type": "code", + "source": [ + "to_graphviz(cpg, port_labels=true, graph_attrs=Dict(\"nodesep\"=>\"2\", \"ranksep\"=>\"2\"))" + ], + "metadata": {}, + "execution_count": 26 + }, + { + "cell_type": "markdown", + "source": [ + "Almost every application of graphs in computer science could be better served by using one of these extensions to the basic graph data structure." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/wiring_diagrams/wd_cset/482eec26.svg b/v0.16.12/generated/wiring_diagrams/wd_cset/482eec26.svg new file mode 100644 index 000000000..a6d914a89 --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/wd_cset/482eec26.svg @@ -0,0 +1,231 @@ + + + + + + +G + + + +n1 + +Box + + + +n12 + +BoxValue + + + +n1->n12 + + +value + + + +n13 + +BoxType + + + +n1->n13 + + +box_type + + + +n2 + +InPort + + + +n2->n1 + + +in_port_box + + + +n10 + +PortValue + + + +n2->n10 + + +in_port_type + + + +n3 + +OutPort + + + +n3->n1 + + +out_port_box + + + +n3->n10 + + +out_port_type + + + +n4 + +OuterInPort + + + +n4->n10 + + +outer_in_port_type + + + +n5 + +OuterOutPort + + + +n5->n10 + + +outer_out_port_type + + + +n6 + +Wire + + + +n6->n2 + + +tgt + + + +n6->n3 + + +src + + + +n11 + +WireValue + + + +n6->n11 + + +wire_value + + + +n7 + +InWire + + + +n7->n2 + + +in_tgt + + + +n7->n4 + + +in_src + + + +n7->n11 + + +in_wire_value + + + +n8 + +OutWire + + + +n8->n3 + + +out_src + + + +n8->n5 + + +out_tgt + + + +n8->n11 + + +out_wire_value + + + +n9 + +PassWire + + + +n9->n4 + + +pass_src + + + +n9->n5 + + +pass_tgt + + + +n9->n11 + + +pass_wire_value + + + diff --git a/v0.16.12/generated/wiring_diagrams/wd_cset/e4ad5b8a.svg b/v0.16.12/generated/wiring_diagrams/wd_cset/e4ad5b8a.svg new file mode 100644 index 000000000..685651e1b --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/wd_cset/e4ad5b8a.svg @@ -0,0 +1,171 @@ + + + + + + +G + + + +n1 + +Box + + + +n2 + +InPort + + + +n2->n1 + + +in_port_box + + + +n10 + +PortValue + + + +n2->n10 + + +in_port_type + + + +n3 + +OutPort + + + +n3->n1 + + +out_port_box + + + +n3->n10 + + +out_port_type + + + +n4 + +OuterInPort + + + +n4->n10 + + +outer_in_port_type + + + +n5 + +OuterOutPort + + + +n5->n10 + + +outer_out_port_type + + + +n6 + +Wire + + + +n6->n2 + + +tgt + + + +n6->n3 + + +src + + + +n7 + +InWire + + + +n7->n2 + + +in_tgt + + + +n7->n4 + + +in_src + + + +n8 + +OutWire + + + +n8->n3 + + +out_src + + + +n8->n5 + + +out_tgt + + + +n9 + +PassWire + + + +n9->n4 + + +pass_src + + + +n9->n5 + + +pass_tgt + + + diff --git a/v0.16.12/generated/wiring_diagrams/wd_cset/index.html b/v0.16.12/generated/wiring_diagrams/wd_cset/index.html new file mode 100644 index 000000000..2a394ebed --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/wd_cset/index.html @@ -0,0 +1,1640 @@ + +Wiring Diagrams as Attributed C-Sets · Catlab.jl

Wiring Diagrams as Attributed C-Sets

Catlab supports many different flavors of diagrammatic syntax. These support the different combinatorial data structures that we use for representing categorical constructions. We will discuss DirectedWiringDiagrams, UndirectedWiringDiagrams, and CPortGraphs in this document.

using Catlab.Theories, Catlab.CategoricalAlgebra
+using Catlab.WiringDiagrams, Catlab.Programs, Catlab.Graphics
+using Catlab.Graphics: Graphviz
+
+draw(d::WiringDiagram) = to_graphviz(d,
+  orientation=LeftToRight,
+  labels=true, label_attr=:xlabel,
+  node_attrs=Graphviz.Attributes(
+    :fontname => "Courier",
+  ),
+  edge_attrs=Graphviz.Attributes(
+    :fontname => "Courier",
+  )
+)
+
+draw(uwd::AbstractUWD) = to_graphviz(uwd, junction_labels=:variable, box_labels=:name)
draw (generic function with 2 methods)

Directed Wiring Diagrams

DWDs are used to represent the morphisms in a symmetric monoidal category. You can get started by presenting a FreeSymmetricMonoidalCategory with the @present macro.

@present P(FreeSymmetricMonoidalCategory) begin
+  (A,B,C,D)::Ob
+  f::Hom(A,B)
+  g::Hom(B,A)
+  h::Hom(A⊗B, C)
+  k::Hom(C,D⊗A)
+end
+generators(P)
8-element Vector{Any}:
+ A
+ B
+ C
+ D
+ f: A → B
+ g: B → A
+ h: A⊗B → C
+ k: C → D⊗A

These presentations are very syntactic objects and expose an API for manipulating expressions.

for g in generators(P)
+  "$g is a $(gat_typeof(g)) with arguments $(gat_type_args(g))"
+end

The gat_typeof function computes the algebraic type of a term by analogy to Base.typeof which computes the Julia type of a value.

homs_P = filter(generators(P)) do g
+  gat_typeof(g) == :Hom
+end
4-element Vector{Any}:
+ f: A → B
+ g: B → A
+ h: A⊗B → C
+ k: C → D⊗A

When the term is a Hom, you can get the domain and codomain of the morphism with the dom and codom functions.

map(homs_P) do f
+  "$f: $(dom(f)) → $(codom(f))"
+end
4-element Vector{String}:
+ "f: A → B"
+ "g: B → A"
+ "h: otimes(A,B) → C"
+ "k: C → otimes(D,A)"

With the presentation you can build up morphism expressions using a formula syntax.

P[:h]⋅P[:k]

\[h \cdot k : A \otimes B \to D \otimes A\]

This syntactic API is useful for manipulating terms in an arbitrary GAT and is the formal language of Catlab for representing and manipulating algebraic structures. However, when we want to work with big expressions in an SMC, the tree structure inherent to formulas is too verbose, and we want to move to a port-graph structure called DirectedWiringDiagrams. This gives us the benefits of combinatorial data structures like graphs with the right expressional power for representing the morphisms in an SMC.

wd = @program P (a::A, b::B) begin
+  c = h(a,b)
+  return k(c)
+end
+
+draw(wd)

Catlab gives you the tools for drawing wiring diagrams. Visualization of wiring diagrams is the oldest part of Catlab and the original motivation for its development. The @program macro allows you to define wiring diagrams using a syntax that feels like Julia code.

wd = @program P (a::A, b::B) begin
+  c = h(a,b)
+  d,a₁ = k(c)
+  return d, f(a₁)
+end
+draw(wd)

The input wires are declared as arguments to the program, and the output wires are declared as returns from the function. Variables that are not consumed or by another function or returned by the program are automatically dropped.

wd = @program P (a::A, b::B) begin
+  c = h(a,b)
+  d,a₁ = k(c)
+  return f(a₁)
+end
+draw(wd)

You can copy a value by using it more than once. This is visualized as a wire being split into two wires.

wd = @program P (b::B) begin
+  h(g(b),b)
+end
+draw(wd)

You can visualize the copy and delete morphisms explicitly with the add_junctions function. The dots with one wire input and multiple outputs are copying values and dots with no wires out are deletions (discarding values). Not all instances of a SymmetricMonoidalCategory support copy and delete, for example, in manufacturing you can't duplicate a resource, and in chemistry you can't discard species. Catlab would enforce that when you tried to interpret the wiring diagram in a specific SMC.

wd = @program P (b::B) begin
+  c = h(g(b),b)
+  d, a₁ = k(c)
+  return f(a₁)
+end
+draw(add_junctions(wd))

For more details about working with wiring diagrams in Catlab, you should look at the other vignettes in this section which explain how wiring diagrams interact with SMC expressions and the basics of constructing and manipulation wiring diagrams.

Diagrams as C-Sets

The underlying data of a wiring diagram is combinatorial. That means we can represent it as a C-Set

wd.diagram
+Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagramACSet{Any, Any, Any, DataType} {Box:4, InPort:5, OutPort:5, OuterInPort:1, OuterOutPort:1, Wire:3, InWire:2, OutWire:1, PassWire:0, PortValue:0, WireValue:0, BoxValue:0, BoxType:0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Boxvaluebox_type
1gBox{Symbol}
2hBox{Symbol}
3kBox{Symbol}
4fBox{Symbol}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
InPortin_port_boxin_port_type
11B
22A
32B
43C
54A
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OutPortout_port_boxout_port_type
11A
22C
33D
43A
54B
+ + + + + + + + + + + + + +
OuterInPortouter_in_port_type
1B
+ + + + + + + + + + + + + +
OuterOutPortouter_out_port_type
1B
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Wiresrctgtwire_value
145nothing
212nothing
324nothing
+ + + + + + + + + + + + + + + + + + + + + + + +
InWirein_srcin_tgtin_wire_value
111nothing
213nothing
+ + + + + + + + + + + + + + + + + +
OutWireout_srcout_tgtout_wire_value
151nothing
+
+

Ok, there is a lot in there. The columns with integer entries are the combinatorial data encoding the connectivity of the wiring diagram. The columns with Symbols in them are encoding the labels for the diagram, the value of a box is the content of the box. Ports have types and wires have values. When we define the wiring diagram with the @program macro, we get a diagram that has labels and types, but no values. These values are initialized to nothing, but could be filled with values to be carried down the wires in an application.

The schema of for wiring diagrams is called SchAttributedWiringDiagrams and is a little overwhelming, so we can explore how to build it up with C-Set schema inheritance.

to_graphviz(SchAttributedWiringDiagram)
Example block output

From the file Catlab/src/WiringDiagrams/Directed.jl

@present SchWiringDiagram(FreeSchema) begin
+  Box::Ob
+  (InPort, OutPort, OuterInPort, OuterOutPort)::Ob
+  (Wire, InWire, OutWire, PassWire)::Ob
+
+  src::Hom(Wire, OutPort)
+  tgt::Hom(Wire, InPort)
+  in_src::Hom(InWire, OuterInPort)
+  in_tgt::Hom(InWire, InPort)
+  out_src::Hom(OutWire, OutPort)
+  out_tgt::Hom(OutWire, OuterOutPort)
+  pass_src::Hom(PassWire, OuterInPort)
+  pass_tgt::Hom(PassWire, OuterOutPort)
+
+  in_port_box::Hom(InPort, Box)
+  out_port_box::Hom(OutPort, Box)
+end
+
+@abstract_acset_type AbstractWiringDiagram <: AbstractGraph
+
+@present SchTypedWiringDiagram <: SchWiringDiagram begin
+  PortValue::AttrType
+  in_port_type::Attr(InPort, PortValue)
+  out_port_type::Attr(OutPort, PortValue)
+  outer_in_port_type::Attr(OuterInPort, PortValue)
+  outer_out_port_type::Attr(OuterOutPort, PortValue)
+end
+
+@present SchAttributedWiringDiagram <: SchTypedWiringDiagram begin
+  WireValue::AttrType
+  BoxValue::AttrType
+  BoxType::AttrType
+
+  value::Attr(Box, BoxValue)
+  box_type::Attr(Box, BoxType)
+  wire_value::Attr(Wire, WireValue)
+  in_wire_value::Attr(InWire, WireValue)
+  out_wire_value::Attr(OutWire, WireValue)
+  pass_wire_value::Attr(PassWire, WireValue)
+end

The bare minimum diagram language is:

to_graphviz(SchWiringDiagram)

And then you can add back in the types.

to_graphviz(SchTypedWiringDiagram)
Example block output

Layout is hard, so if you want to understand the SchAttributedWiringDiagrams, you should do the layout by hand as an exercise.

We can create our own version of the theory of DWDs to see how it works:

@present MySchWiringDiagram(FreeSchema) begin
+  Box::Ob
+  (InPort, OutPort, OuterInPort, OuterOutPort)::Ob
+  (Wire, InWire, OutWire, PassWire)::Ob
+
+  src::Hom(Wire, OutPort)
+  tgt::Hom(Wire, InPort)
+  in_src::Hom(InWire, OuterInPort)
+  in_tgt::Hom(InWire, InPort)
+  out_src::Hom(OutWire, OutPort)
+  out_tgt::Hom(OutWire, OuterOutPort)
+  pass_src::Hom(PassWire, OuterInPort)
+  pass_tgt::Hom(PassWire, OuterOutPort)
+
+  in_port_box::Hom(InPort, Box)
+  out_port_box::Hom(OutPort, Box)
+end
Presentation{Catlab.Theories.ThSchema.Meta.T, Symbol}(Catlab.Theories.FreeSchema, (Ob = Catlab.Theories.FreeSchema.Ob{:generator}[Box, InPort, OutPort, OuterInPort, OuterOutPort, Wire, InWire, OutWire, PassWire], Hom = Catlab.Theories.FreeSchema.Hom{:generator}[src, tgt, in_src, in_tgt, out_src, out_tgt, pass_src, pass_tgt, in_port_box, out_port_box], AttrType = Catlab.Theories.FreeSchema.AttrType{:generator}[], Attr = Catlab.Theories.FreeSchema.Attr{:generator}[]), Dict(:InPort => (:Ob => 2), :InWire => (:Ob => 7), :in_port_box => (:Hom => 9), :Box => (:Ob => 1), :OuterOutPort => (:Ob => 5), :in_src => (:Hom => 3), :in_tgt => (:Hom => 4), :src => (:Hom => 1), :OuterInPort => (:Ob => 4), :out_port_box => (:Hom => 10)…), Pair[])

If your application of wiring diagrams needs to attach numeric or textual information to the boxes of a wiring diagram, you would extend the SchWiringDiagram with the attributes that you need. That will give you a custom data structure that has those fields. One of the goals of Catlab is to make it so much easier to generate custom data structures that interoperate, that you don't need to create generic structures that can be used for many purposes. Just snap your fingers and create a new structure perfectly tailored to your needs, when your needs change, snap again to get a new version of that structure.

The @acset_type macro does the hard work of generating the data structure and accessors and mutators for you. The form of this call is @acset_type NewStructName(Schema, index=[morphisms in Schema]) <: Supertype. You should index any morphism where you need to use incident frequently. For wiring diagrams you will often want to know what all the wires that are incident to a port.

@acset_type MyWiringDiagramACSet(MySchWiringDiagram,
+  index=[:src, :tgt, :in_src, :in_tgt, :out_src, :out_tgt, :pass_src, :pass_tgt]) <: WiringDiagrams.DirectedWiringDiagrams.AbstractWiringDiagram
Main.MyWiringDiagramACSet

We get the @acset macro from Catlab and can create DWDs by hand. It is very tedious, which is why the @program macro exists!

md = @acset MyWiringDiagramACSet begin
+  Box = 3
+  InPort = 6
+  OutPort = 3
+  Wire = 3
+  src = [1,2,3]
+  tgt = [3,4,5]
+  in_port_box = [1,1,2,2,3,3]
+  out_port_box = [1,2,3]
+end
+Main.__atexample__named__wd_cset.MyWiringDiagramACSet {Box:3, InPort:6, OutPort:3, OuterInPort:0, OuterOutPort:0, Wire:3, InWire:0, OutWire:0, PassWire:0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
InPortin_port_box
11
21
32
42
53
63
+ + + + + + + + + + + + + + + + + + + + + +
OutPortout_port_box
11
22
33
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Wiresrctgt
113
224
335
+
+

Undirected Wiring Diagrams

A much simpler structure than DWDs are known as undirected wiring diagrams. They are called undirected because ports boxes have one set of ports that aren't divided into inputs and outputs, and the wires are undirected. Wires connect junctions to ports (which live on boxes).

to_graphviz(SchUWD)

These UWDs are combinatorial syntax for relations. The junctions are variables and the boxes are the relations. A relation R ⊆ X × Y has two ports one for the value of X and one for the value of Y. The expression R(x:X, y:Y) says to connect the X port of R to the junction for the variable x, and the Y port of R to the y variable junction. If two ports are attached to the same junction, then you have a constraint that those values must be equal. The outer ports are the components of the final relation. For example the following UWD encodes the relation {(x,y,z) | R(x,y) and S(y,z) for all x∈X, y∈Y, z∈Z}.

uwd = @relation (x, y, z) begin
+  R(x,y)
+  S(y,z)
+end
+Catlab.Programs.RelationalPrograms.UntypedUnnamedRelationDiagram{Symbol, Symbol} {Box:2, Port:4, OuterPort:3, Junction:3, Name:0, VarName:0} + + + + + + + + + + + + + + + + + +
Boxname
1R
2S
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Portboxjunction
111
212
322
423
+ + + + + + + + + + + + + + + + + + + + + +
OuterPortouter_junction
11
22
33
+ + + + + + + + + + + + + + + + + + + + + +
Junctionvariable
1x
2y
3z
+
+

These UWDs are drawn with circular boxes and undirected wires. Note that since all wires go from junction to port, they are not symmetric wires.

draw(uwd)

By adding more relations we can get bigger relations.

uwd₂ = @relation (x, z) begin
+  R(x,y)
+  S(y,z)
+  T(x,z,y)
+end
+Catlab.Programs.RelationalPrograms.UntypedUnnamedRelationDiagram{Symbol, Symbol} {Box:3, Port:7, OuterPort:2, Junction:3, Name:0, VarName:0} + + + + + + + + + + + + + + + + + + + + + +
Boxname
1R
2S
3T
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Portboxjunction
111
213
323
422
531
632
733
+ + + + + + + + + + + + + + + + + +
OuterPortouter_junction
11
22
+ + + + + + + + + + + + + + + + + + + + + +
Junctionvariable
1x
2z
3y
+
+

Not all of the junctions have to be exposed to the outside world. Note that there is no distinction between arguments and return values in the relation macro. This is because relations are inherently undirected, unlike functions.

draw(uwd₂)

Circular Port Graphs

CPGs are the natural data structure for representing process of interconnected systems that share information along wires, but send different information to their different neighbors.

to_graphviz(SchCPortGraph)

They are also a kind of CSet, so we can use the @acset macro to construct them.

cpg = @acset CPortGraph begin
+  Box = 3
+  Port = 6
+  Wire = 5
+
+  box = [1,1,2,2,3,3]
+  src = [1,2,5,2,6]
+  tgt = [3,4,2,4,1]
+end
+CPortGraph {Box:3, Port:6, Wire:5} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Portbox
11
21
32
42
53
63
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Wiresrctgt
113
224
352
424
561
+
+

the layout for CPGs is not great with graphviz.

to_graphviz(cpg, port_labels=true, graph_attrs=Dict("nodesep"=>"2", "ranksep"=>"2"))

Almost every application of graphs in computer science could be better served by using one of these extensions to the basic graph data structure.

diff --git a/v0.16.12/generated/wiring_diagrams/wiring_diagram_basics.ipynb b/v0.16.12/generated/wiring_diagrams/wiring_diagram_basics.ipynb new file mode 100644 index 000000000..1ecac515e --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/wiring_diagram_basics.ipynb @@ -0,0 +1,978 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Basics of wiring diagrams\n", + "\n", + "\n", + "using GATlab, you can create, manipulate, serialize, and visualize *wiring\n", + "diagrams*, also known as [string\n", + "diagrams](https://ncatlab.org/nlab/show/string+diagram). The flexible data\n", + "structure for wiring diagrams allows arbitrary data to be attached to boxes,\n", + "ports, and wires, and supports recursively nested diagrams.\n", + "\n", + "You can interact with wiring diagrams using two different progamming\n", + "interfaces:\n", + "\n", + "1. **Categorical**: A high-level, functional interface expressed in terms of\n", + " categorical concepts, such as composition (`compose`), monoidal products\n", + " (`otimes`), duplication (`mcopy`), and deletion (`delete`).\n", + "\n", + "2. **Imperative**: A lower-level, mutating interface to directly manipulate\n", + " boxes, ports, and wires, via operations like adding boxes (`add_box`) and\n", + " wires (`add_wire`).\n", + "\n", + "In this notebook, we introduce both interfaces. We do not explicitly cover the\n", + "visualization API, although for illustrative purposes we will draw wiring\n", + "diagrams using Graphviz. Thus, you should install\n", + "[Graphviz](https://www.graphviz.org/) if you wish to run this notebook." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "show_diagram (generic function with 1 method)" + }, + "metadata": {}, + "execution_count": 1 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.WiringDiagrams\n", + "\n", + "using Catlab.Graphics\n", + "import Catlab.Graphics: Graphviz\n", + "\n", + "show_diagram(d::WiringDiagram) = to_graphviz(d,\n", + " orientation=LeftToRight,\n", + " labels=true, label_attr=:xlabel,\n", + " node_attrs=Graphviz.Attributes(\n", + " :fontname => \"Courier\",\n", + " ),\n", + " edge_attrs=Graphviz.Attributes(\n", + " :fontname => \"Courier\",\n", + " )\n", + ")" + ], + "metadata": {}, + "execution_count": 1 + }, + { + "cell_type": "markdown", + "source": [ + "## Data structures\n", + "\n", + "The basic building blocks of a wiring diagram are boxes, ports, and wires. The\n", + "top-level data structure is `WiringDiagram`, defined in the module\n", + "`Catlab.WiringDiagrams`. A wiring diagram consists of boxes (usually of type\n", + "`Box`) connected by wires (of type `Wire`). Each box has a sequence of input\n", + "ports and a sequence of output ports, as does the wiring diagram itself. The\n", + "wires have sources and targets, both of which consist of a box and a port on\n", + "that box.\n", + "\n", + "The boxes in a wiring diagram are indexed by integer IDs. Boxes can be\n", + "retrieved by ID, and wires refer to boxes using their IDs. Two special IDs,\n", + "obtained by `input_id` and `output_id` methods, refer to the inputs and\n", + "outputs of the diagram itself. In this way, wires can connect the (inner)\n", + "boxes of a diagram to the diagram's \"outer box\".\n", + "\n", + "The `WiringDiagram` data structure is an elaborate wrapper around a directed\n", + "graph from [Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl).\n", + "The underlying `DiGraph` object can be accessed using the `graph` method. The\n", + "vertices of this graph are exactly the box IDs. The graph should never be\n", + "mutated directly, on pain of creating inconsistent state, but it does allow\n", + "convenient access to the large array of graph algorithms supported by Graphs.\n", + "\n", + "All this is somewhat abstract but should become clearer as we see concrete\n", + "examples." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Categorical interface\n", + "\n", + "In this example, the wiring diagrams will carry symbolic expressions (of type\n", + "`Catlab.ObExpr` and `Catlab.HomExpr`)." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "f: A → B", + "text/latex": "$f : A \\to B$" + }, + "metadata": {}, + "execution_count": 2 + } + ], + "cell_type": "code", + "source": [ + "using Catlab.Theories\n", + "\n", + "A, B, C, D = Ob(FreeBiproductCategory, :A, :B, :C, :D)\n", + "f = Hom(:f, A, B)\n", + "g = Hom(:g, B, C)\n", + "h = Hom(:h, C, D)\n", + "\n", + "f" + ], + "metadata": {}, + "execution_count": 2 + }, + { + "cell_type": "markdown", + "source": [ + "### Generators\n", + "\n", + "Convert each of the morphism generators into a diagram with a single box." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:A], [:B], \n[ -2 => {inputs},\n -1 => {outputs},\n 1 => Box(:f, [:A], [:B]) ],\n[ Wire((-2,1) => (1,1)),\n Wire((1,1) => (-1,1)) ])" + }, + "metadata": {}, + "execution_count": 3 + } + ], + "cell_type": "code", + "source": [ + "f, g, h = to_wiring_diagram(f), to_wiring_diagram(g), to_wiring_diagram(h)\n", + "f" + ], + "metadata": {}, + "execution_count": 3 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(f)" + ], + "metadata": {}, + "execution_count": 4 + }, + { + "cell_type": "markdown", + "source": [ + "### Composition" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:A], [:C], \n[ -2 => {inputs},\n -1 => {outputs},\n 1 => Box(:f, [:A], [:B]),\n 2 => Box(:g, [:B], [:C]) ],\n[ Wire((-2,1) => (1,1)),\n Wire((1,1) => (2,1)),\n Wire((2,1) => (-1,1)) ])" + }, + "metadata": {}, + "execution_count": 5 + } + ], + "cell_type": "code", + "source": [ + "compose(f,g)" + ], + "metadata": {}, + "execution_count": 5 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e3\", :xlabel => \"C\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(compose(f,g))" + ], + "metadata": {}, + "execution_count": 6 + }, + { + "cell_type": "markdown", + "source": [ + "### Monoidal products" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:A,:C], [:B,:D], \n[ -2 => {inputs},\n -1 => {outputs},\n 1 => Box(:f, [:A], [:B]),\n 2 => Box(:h, [:C], [:D]) ],\n[ Wire((-2,1) => (1,1)),\n Wire((-2,2) => (2,1)),\n Wire((1,1) => (-1,1)),\n Wire((2,1) => (-1,2)) ])" + }, + "metadata": {}, + "execution_count": 7 + } + ], + "cell_type": "code", + "source": [ + "otimes(f,h)" + ], + "metadata": {}, + "execution_count": 7 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e2\", :xlabel => \"C\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"D\", :id => \"e4\", :xlabel => \"D\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "D\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(otimes(f,h))" + ], + "metadata": {}, + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "### Copy and merge, delete and create" + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:B], [:B,:B], \n[ -2 => {inputs},\n -1 => {outputs},\n ],\n[ Wire((-2,1) => (-1,1)),\n Wire((-2,1) => (-1,2)) ])" + }, + "metadata": {}, + "execution_count": 9 + } + ], + "cell_type": "code", + "source": [ + "mcopy(codom(f),2)" + ], + "metadata": {}, + "execution_count": 9 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e1\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n0out2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(mcopy(codom(f),2))" + ], + "metadata": {}, + "execution_count": 10 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(compose(f, mcopy(codom(f),2)))" + ], + "metadata": {}, + "execution_count": 11 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e2\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e4\", :xlabel => \"B\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n2:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(compose(mcopy(dom(f),2), otimes(f,f)))" + ], + "metadata": {}, + "execution_count": 12 + }, + { + "cell_type": "markdown", + "source": [ + "## Imperative interface\n", + "\n", + "We now show how to manipulate wiring diagrams using the low-level, imperative\n", + "interface. The diagrams will carry Julia symbols." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Box(:f, [:A], [:B])" + }, + "metadata": {}, + "execution_count": 13 + } + ], + "cell_type": "code", + "source": [ + "f = Box(:f, [:A], [:B])\n", + "g = Box(:g, [:B], [:C])\n", + "h = Box(:h, [:C], [:D])\n", + "\n", + "f" + ], + "metadata": {}, + "execution_count": 13 + }, + { + "cell_type": "markdown", + "source": [ + "### Composition\n", + "\n", + "For example, here is how to manually construct a composition of two boxes.\n", + "\n", + "The `add_box!` method adds a box to a wiring diagrams and returns the ID\n", + "assigned to the box. How the boxes are indexed is an implementation detail\n", + "that you should not rely on; use the IDs that the system gives you." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "2" + }, + "metadata": {}, + "execution_count": 14 + } + ], + "cell_type": "code", + "source": [ + "d = WiringDiagram([:A], [:C])\n", + "\n", + "fv = add_box!(d, f)\n", + "gv = add_box!(d, g)\n", + "\n", + "add_wires!(d, [\n", + " (input_id(d),1) => (fv,1),\n", + " (fv,1) => (gv,1),\n", + " (gv,1) => (output_id(d),1),\n", + "])\n", + "\n", + "nboxes(d)" + ], + "metadata": {}, + "execution_count": 14 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "3" + }, + "metadata": {}, + "execution_count": 15 + } + ], + "cell_type": "code", + "source": [ + "nwires(d)" + ], + "metadata": {}, + "execution_count": 15 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "WiringDiagram([:A], [:C], \n[ -2 => {inputs},\n -1 => {outputs},\n 1 => Box(:f, [:A], [:B]),\n 2 => Box(:g, [:B], [:C]) ],\n[ Wire((-2,1) => (1,1)),\n Wire((1,1) => (2,1)),\n Wire((2,1) => (-1,1)) ])" + }, + "metadata": {}, + "execution_count": 16 + } + ], + "cell_type": "code", + "source": [ + "d" + ], + "metadata": {}, + "execution_count": 16 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"g\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
g
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e2\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e3\", :xlabel => \"C\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "g\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n2:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out1:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(d)" + ], + "metadata": {}, + "execution_count": 17 + }, + { + "cell_type": "markdown", + "source": [ + "### Products\n", + "\n", + "Here is how to manually construct a product of two boxes." + ], + "metadata": {} + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "WiringDiagram([:A,:C], [:B,:D], \n[ -2 => {inputs},\n -1 => {outputs},\n 1 => Box(:f, [:A], [:B]),\n 2 => Box(:h, [:C], [:D]) ],\n[ Wire((-2,1) => (1,1)),\n Wire((-2,2) => (2,1)),\n Wire((1,1) => (-1,1)),\n Wire((2,1) => (-1,2)) ])" + }, + "metadata": {}, + "execution_count": 18 + } + ], + "cell_type": "code", + "source": [ + "d = WiringDiagram([:A,:C], [:B,:D])\n", + "\n", + "fv = add_box!(d, f)\n", + "hv = add_box!(d, h)\n", + "\n", + "add_wires!(d, [\n", + " (input_id(d),1) => (fv,1),\n", + " (input_id(d),2) => (hv,1),\n", + " (fv,1) => (output_id(d),1),\n", + " (hv,1) => (output_id(d),2),\n", + "])\n", + "\n", + "d" + ], + "metadata": {}, + "execution_count": 18 + }, + { + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": "Catlab.Graphics.Graphviz.Graph(\"G\", true, \"dot\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0in1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in1\")), Catlab.Graphics.Graphviz.Node(\"n0in2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"in2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"source\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Subgraph(\"\", Catlab.Graphics.Graphviz.Statement[Catlab.Graphics.Graphviz.Node(\"n0out1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out1\")), Catlab.Graphics.Graphviz.Node(\"n0out2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:id => \"out2\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}())], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:rank => \"sink\", :rankdir => \"TB\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\", :shape => \"none\", :label => \"\", :width => \"0\", :height => \"0.333\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:style => \"invis\")), Catlab.Graphics.Graphviz.Node(\"n1\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"f\", :fillcolor => \"white\", :id => \"n1\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
f
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:color => \"black\", :comment => \"h\", :fillcolor => \"white\", :id => \"n2\", :label => Catlab.Graphics.Graphviz.Html(\"\\n\\n\\n\\n\\n\\n
h
\"), :style => \"solid\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in1\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n1\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"A\", :id => \"e1\", :xlabel => \"A\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n0in2\", \"e\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n2\", \"in1\", \"w\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"C\", :id => \"e2\", :xlabel => \"C\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n1\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out1\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"B\", :id => \"e3\", :xlabel => \"B\")), Catlab.Graphics.Graphviz.Edge(Catlab.Graphics.Graphviz.NodeID[Catlab.Graphics.Graphviz.NodeID(\"n2\", \"out1\", \"e\"), Catlab.Graphics.Graphviz.NodeID(\"n0out2\", \"w\", \"\")], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:comment => \"D\", :id => \"e4\", :xlabel => \"D\"))], OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Serif\", :rankdir => \"LR\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fontname => \"Courier\", :shape => \"none\", :width => \"0\", :height => \"0\", :margin => \"0\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:arrowsize => \"0.5\", :fontname => \"Courier\"))", + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1\n", + "\n", + "f\n", + "\n", + "\n", + "\n", + "\n", + "n0in1:e->n1:w\n", + "\n", + "\n", + "A\n", + "\n", + "\n", + "\n", + "\n", + "n2\n", + "\n", + "h\n", + "\n", + "\n", + "\n", + "\n", + "n0in2:e->n2:w\n", + "\n", + "\n", + "C\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "n1:e->n0out1:w\n", + "\n", + "\n", + "B\n", + "\n", + "\n", + "\n", + "\n", + "n2:e->n0out2:w\n", + "\n", + "\n", + "D\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ], + "cell_type": "code", + "source": [ + "show_diagram(d)" + ], + "metadata": {}, + "execution_count": 19 + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.4" + }, + "kernelspec": { + "name": "julia-1.10", + "display_name": "Julia 1.10.4", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/v0.16.12/generated/wiring_diagrams/wiring_diagram_basics/index.html b/v0.16.12/generated/wiring_diagrams/wiring_diagram_basics/index.html new file mode 100644 index 000000000..474a70d6a --- /dev/null +++ b/v0.16.12/generated/wiring_diagrams/wiring_diagram_basics/index.html @@ -0,0 +1,509 @@ + +Basics of wiring diagrams · Catlab.jl

Basics of wiring diagrams

using GATlab, you can create, manipulate, serialize, and visualize wiring diagrams, also known as string diagrams. The flexible data structure for wiring diagrams allows arbitrary data to be attached to boxes, ports, and wires, and supports recursively nested diagrams.

You can interact with wiring diagrams using two different progamming interfaces:

  1. Categorical: A high-level, functional interface expressed in terms of categorical concepts, such as composition (compose), monoidal products (otimes), duplication (mcopy), and deletion (delete).

  2. Imperative: A lower-level, mutating interface to directly manipulate boxes, ports, and wires, via operations like adding boxes (add_box) and wires (add_wire).

In this notebook, we introduce both interfaces. We do not explicitly cover the visualization API, although for illustrative purposes we will draw wiring diagrams using Graphviz. Thus, you should install Graphviz if you wish to run this notebook.

using Catlab.WiringDiagrams
+
+using Catlab.Graphics
+import Catlab.Graphics: Graphviz
+
+show_diagram(d::WiringDiagram) = to_graphviz(d,
+  orientation=LeftToRight,
+  labels=true, label_attr=:xlabel,
+  node_attrs=Graphviz.Attributes(
+    :fontname => "Courier",
+  ),
+  edge_attrs=Graphviz.Attributes(
+    :fontname => "Courier",
+  )
+)
show_diagram (generic function with 1 method)

Data structures

The basic building blocks of a wiring diagram are boxes, ports, and wires. The top-level data structure is WiringDiagram, defined in the module Catlab.WiringDiagrams. A wiring diagram consists of boxes (usually of type Box) connected by wires (of type Wire). Each box has a sequence of input ports and a sequence of output ports, as does the wiring diagram itself. The wires have sources and targets, both of which consist of a box and a port on that box.

The boxes in a wiring diagram are indexed by integer IDs. Boxes can be retrieved by ID, and wires refer to boxes using their IDs. Two special IDs, obtained by input_id and output_id methods, refer to the inputs and outputs of the diagram itself. In this way, wires can connect the (inner) boxes of a diagram to the diagram's "outer box".

The WiringDiagram data structure is an elaborate wrapper around a directed graph from Graphs.jl. The underlying DiGraph object can be accessed using the graph method. The vertices of this graph are exactly the box IDs. The graph should never be mutated directly, on pain of creating inconsistent state, but it does allow convenient access to the large array of graph algorithms supported by Graphs.

All this is somewhat abstract but should become clearer as we see concrete examples.

Categorical interface

In this example, the wiring diagrams will carry symbolic expressions (of type Catlab.ObExpr and Catlab.HomExpr).

using Catlab.Theories
+
+A, B, C, D = Ob(FreeBiproductCategory, :A, :B, :C, :D)
+f = Hom(:f, A, B)
+g = Hom(:g, B, C)
+h = Hom(:h, C, D)
+
+f

\[f : A \to B\]

Generators

Convert each of the morphism generators into a diagram with a single box.

f, g, h = to_wiring_diagram(f), to_wiring_diagram(g), to_wiring_diagram(h)
+f
WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:A], [:B], 
+[ -2 => {inputs},
+  -1 => {outputs},
+  1 => Box(:f, [:A], [:B]) ],
+[ Wire((-2,1) => (1,1)),
+  Wire((1,1) => (-1,1)) ])
show_diagram(f)

Composition

compose(f,g)
WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:A], [:C], 
+[ -2 => {inputs},
+  -1 => {outputs},
+  1 => Box(:f, [:A], [:B]),
+  2 => Box(:g, [:B], [:C]) ],
+[ Wire((-2,1) => (1,1)),
+  Wire((1,1) => (2,1)),
+  Wire((2,1) => (-1,1)) ])
show_diagram(compose(f,g))

Monoidal products

otimes(f,h)
WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:A,:C], [:B,:D], 
+[ -2 => {inputs},
+  -1 => {outputs},
+  1 => Box(:f, [:A], [:B]),
+  2 => Box(:h, [:C], [:D]) ],
+[ Wire((-2,1) => (1,1)),
+  Wire((-2,2) => (2,1)),
+  Wire((1,1) => (-1,1)),
+  Wire((2,1) => (-1,2)) ])
show_diagram(otimes(f,h))

Copy and merge, delete and create

mcopy(codom(f),2)
WiringDiagram{Catlab.Theories.ThBiproductCategory.Meta.T}([:B], [:B,:B], 
+[ -2 => {inputs},
+  -1 => {outputs},
+   ],
+[ Wire((-2,1) => (-1,1)),
+  Wire((-2,1) => (-1,2)) ])
show_diagram(mcopy(codom(f),2))
show_diagram(compose(f, mcopy(codom(f),2)))
show_diagram(compose(mcopy(dom(f),2), otimes(f,f)))

Imperative interface

We now show how to manipulate wiring diagrams using the low-level, imperative interface. The diagrams will carry Julia symbols.

f = Box(:f, [:A], [:B])
+g = Box(:g, [:B], [:C])
+h = Box(:h, [:C], [:D])
+
+f
Box(:f, [:A], [:B])

Composition

For example, here is how to manually construct a composition of two boxes.

The add_box! method adds a box to a wiring diagrams and returns the ID assigned to the box. How the boxes are indexed is an implementation detail that you should not rely on; use the IDs that the system gives you.

d = WiringDiagram([:A], [:C])
+
+fv = add_box!(d, f)
+gv = add_box!(d, g)
+
+add_wires!(d, [
+  (input_id(d),1) => (fv,1),
+  (fv,1) => (gv,1),
+  (gv,1) => (output_id(d),1),
+])
+
+nboxes(d)
2
nwires(d)
3
d
WiringDiagram([:A], [:C], 
+[ -2 => {inputs},
+  -1 => {outputs},
+  1 => Box(:f, [:A], [:B]),
+  2 => Box(:g, [:B], [:C]) ],
+[ Wire((-2,1) => (1,1)),
+  Wire((1,1) => (2,1)),
+  Wire((2,1) => (-1,1)) ])
show_diagram(d)

Products

Here is how to manually construct a product of two boxes.

d = WiringDiagram([:A,:C], [:B,:D])
+
+fv = add_box!(d, f)
+hv = add_box!(d, h)
+
+add_wires!(d, [
+  (input_id(d),1) => (fv,1),
+  (input_id(d),2) => (hv,1),
+  (fv,1) => (output_id(d),1),
+  (hv,1) => (output_id(d),2),
+])
+
+d
WiringDiagram([:A,:C], [:B,:D], 
+[ -2 => {inputs},
+  -1 => {outputs},
+  1 => Box(:f, [:A], [:B]),
+  2 => Box(:h, [:C], [:D]) ],
+[ Wire((-2,1) => (1,1)),
+  Wire((-2,2) => (2,1)),
+  Wire((1,1) => (-1,1)),
+  Wire((2,1) => (-1,2)) ])
show_diagram(d)
diff --git a/v0.16.12/index.html b/v0.16.12/index.html new file mode 100644 index 000000000..2d9736f27 --- /dev/null +++ b/v0.16.12/index.html @@ -0,0 +1,23 @@ + +Catlab.jl · Catlab.jl

Catlab.jl

Catlab.jl is a framework for applied and computational category theory, written in the Julia language. Catlab provides a programming library and interactive interface for applications of category theory to scientific and engineering fields. It emphasizes monoidal categories due to their wide applicability but can support any categorical structure that is formalizable as a generalized algebraic theory.

What is Catlab?

Catlab is, or will eventually be, the following things.

Programming library: First and foremost, Catlab provides data structures, algorithms, and serialization for applied category theory. Macros offer a convenient syntax for specifying categorical doctrines and type-safe symbolic manipulation systems. Wiring diagrams (aka string diagrams) are supported through specialized data structures and can be serialized to and from GraphML (an XML-based format) and JSON.

Interactive computing environment: Catlab can also be used interactively in Jupyter notebooks. Symbolic expressions are displayed using LaTeX and wiring diagrams are visualized using Compose.jl, Graphviz, or TikZ.

Computer algebra system: Catlab will serve as a computer algebra system for categorical algebra. Unlike most computer algebra systems, all expressions are typed using fragment of dependent type theory called generalized algebraic theories. We will implement core algorithms for solving word problems and reducing expressions to normal form with respect to several important doctrines, such as those of categories and of symmetric monoidal categories. For the computer algebra of classical abstract algebra, see AbstractAlgebra.jl and Nemo.jl.

What is Catlab not?

Catlab is not currently any of the following things, although we do not rule out that it could eventually evolve in these directions.

Automated theorem prover: Although there is some overlap between computer algebra and automated theorem proving, Catlab cannot be considered a theorem prover because it does not produce formal certificates of correctness (aka proofs).

Proof assistant: Likewise, Catlab is not a proof assistant because it does not produce formally verifiable proofs. Formal verification is not within scope of the project.

Graphical user interface: Catlab does not provide a wiring diagram editor or other graphical user interface. It is primarily a programming library, not a user-facing application. However, there is another project in the AlgebraicJulia ecosystem, Semagrams.jl which does provide graphical user interfaces for interacting with wiring diagrams, Petri nets, and the like.

What is a GAT?

See GATlab documentation

Conventions

In several places in Catlab, we use what we call "Abstract Field Convention". Instead of doing the following:

struct Pair{A}
+  x1::A
+  x2::A
+end
+
+add(xs::Pair) = xs.x1 + xs.x2
+
+const IntPair = Pair{Int}

which leads to potentially longer and longer type names as the type parameters increase in size, we do

"""
+Abstract Fields
+- x1::A
+- x2::A
+"""
+abstract type Pair{A} end
+
+add(xs::Pair) = xs.x1 + xs.x2
+
+struct IntPair <: Pair{Int}
+  x1::Int
+  x2::Int
+end

That is, we assume that all subtypes of a certain abstract types have the same field names, and are organized in roughly the same way. There is no way of enforcing this within Julia, so instead we leave a comment on the abstract type to document that we are working this way.

Note that this is contrary to the standard wisdom in Julia that one should as much as possible access structs through methods, not field accesses. The reason why we do not do this here is twofold. First of all, sometimes it can be annoying to write out the trivial field-access methods in addition to defining the struct. For instance, we have 12 different structs in src/acsets/ColumnImplementations.jl that all are subtypes of an Abstract Field Convention abstract type. It would be 24 lines of boilerplate to write out the field accessors for these types with little appreciable benefit. The second reason is that the Abstract Field Convention is a stronger guarantee than an interface: we are claiming that any subtype has precisely these fields in this order, and no others! This is essential for defining methods like copy, which might be defined as follows.

function copy(p::T) where {T<:Pair}
+  T(p.x1, p.x2)
+end

So the Abstract Field Convention is stronger than a normal interface. It's not really about encapsulating data, it's more about cutting down on long names in debug messages.

Table of Contents

diff --git a/v0.16.12/objects.inv b/v0.16.12/objects.inv new file mode 100644 index 000000000..cff7be7f8 Binary files /dev/null and b/v0.16.12/objects.inv differ diff --git a/v0.16.12/search_index.js b/v0.16.12/search_index.js new file mode 100644 index 000000000..cc0a37ba5 --- /dev/null +++ b/v0.16.12/search_index.js @@ -0,0 +1,3 @@ +var documenterSearchIndex = {"docs": +[{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"EditURL = \"../../../literate/graphics/tikz_wiring_diagrams.jl\"","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Drawing-wiring-diagrams-in-TikZ","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"(Image: )","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"Catlab can draw morphism expressions as TikZ pictures. To use this feature, LaTeX must be installed and the Julia package TikzPictures.jl must be loaded.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"For best results, it is recommended to load the packages Convex.j and SCS.jl. When available they are used to optimize the layout of the outer ports.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"using Catlab.WiringDiagrams, Catlab.Graphics\n\nimport Convex, SCS\nimport TikzPictures","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Examples","page":"Drawing wiring diagrams in TikZ","title":"Examples","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/#Symmetric-monoidal-category","page":"Drawing wiring diagrams in TikZ","title":"Symmetric monoidal category","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"using Catlab.Theories\n\nA, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)\nf, g = Hom(:f, A, B), Hom(:g, B, A);\nnothing #hide","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"To start, here are a few very simple examples.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f, labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f⋅g, labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f⊗g, labels=true, orientation=TopToBottom)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"Here is a more complex example, involving generators with compound domains and codomains.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"h, k = Hom(:h, C, D), Hom(:k, D, C)\nm, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)\nq = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)\n\nto_tikz((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"Identities and braidings appear as wires.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(id(A), labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(braid(A,B), labels=true, labels_pos=0.25)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"The isomorphism A otimes B otimes C to C otimes B otimes A induced by the permutation (3 2 1) is a composite of braidings and identities.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))\n\nto_tikz(σ, arrowtip=\"Stealth\", arrowtip_pos=\"-0.1pt\",\n labels=true, labels_pos=\"0.1pt\")","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"By default, anchor points are added along identity and braiding wires to reproduce the expression structure in the layout. The anchors can be disabled to get a more \"unbiased\" layout.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(σ, anchor_wires=false, arrowtip=\"Stealth\", arrowtip_pos=\"-0.1pt\",\n labels=true, labels_pos=\"0.1pt\")","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Biproduct-category","page":"Drawing wiring diagrams in TikZ","title":"Biproduct category","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)\nf = Hom(:f, A, B)\n\nto_tikz(mcopy(A), labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(delete(A), labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(mcopy(A)⋅(f⊗f)⋅mmerge(B), labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(mcopy(A⊗B), orientation=TopToBottom, labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(mcopy(A⊗B⊗C), orientation=TopToBottom, labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Compact-closed-category","page":"Drawing wiring diagrams in TikZ","title":"Compact closed category","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"The unit and co-unit of a compact closed category appear as caps and cups.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"A, B = Ob(FreeCompactClosedCategory, :A, :B)\n\nto_tikz(dunit(A), arrowtip=\"Stealth\", labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(dcounit(A), arrowtip=\"Stealth\", labels=true)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"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:","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"A, B = Ob(FreeBicategoryRelations, :A, :B)\nf = Hom(:f, A, B)\n\nto_tikz((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Abelian-bicategory-of-relations","page":"Drawing wiring diagrams in TikZ","title":"Abelian bicategory of relations","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"In an abelian bicategory of relations, such as the category of linear 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.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"X = Ob(FreeAbelianBicategoryRelations, :X)\n\nto_tikz(plus(X) ⋅ mcopy(X))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz((mcopy(X)⊕mcopy(X)) ⋅ (id(X)⊕swap(X,X)⊕id(X)) ⋅ (plus(X)⊕plus(X)))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Custom-styles","page":"Drawing wiring diagrams in TikZ","title":"Custom styles","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"The visual appearance of wiring diagrams can be customized using the builtin options or by redefining the TikZ styles for the boxes or wires.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"A, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)\nf, g = Hom(:f, A, B), Hom(:g, B, A)\n\npic = to_tikz(f⋅g, styles=Dict(\n \"box\" => [\"draw\", \"fill\"=>\"{rgb,255: red,230; green,230; blue,250}\"],\n))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"X = Ob(FreeAbelianBicategoryRelations, :X)\n\nto_tikz(plus(X) ⋅ mcopy(X), styles=Dict(\n \"junction\" => [\"circle\", \"draw\", \"fill\"=>\"red\", \"inner sep\"=>\"0\"],\n \"variant junction\" => [\"circle\", \"draw\", \"fill\"=>\"blue\", \"inner sep\"=>\"0\"],\n))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"By default, the boxes are rectangular (:rectangle). Other available shapes include circles (:circle), ellipses (:ellipse), triangles (:triangle, :invtriangle), and trapezoids (:trapezium, :invtrapezium).","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f⋅g, default_box_shape=:circle)","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f⋅g, rounded_boxes=false, box_shapes=Dict(\n f => :triangle, g => :invtriangle,\n))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f⋅g, orientation=TopToBottom, rounded_boxes=false, box_shapes=Dict(\n f => :triangle, g => :invtriangle,\n))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"to_tikz(f⋅g, box_shapes=Dict(\n f => :invtrapezium, g => :trapezium,\n))","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/#Output-formats","page":"Drawing wiring diagrams in TikZ","title":"Output formats","text":"","category":"section"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"The function to_tikz returns an object of type TikZ.Document, representing a TikZ picture and its TikZ library dependencies as an abstract syntax tree. When displayed interactively, this object is compiled by LaTeX to PDF and then converted to SVG.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"To generate the LaTeX source code, use the builtin pretty-printer. This feature does not require LaTeX or TikzPictures.jl to be installed.","category":"page"},{"location":"generated/graphics/tikz_wiring_diagrams/","page":"Drawing wiring diagrams in TikZ","title":"Drawing wiring diagrams in TikZ","text":"import Catlab.Graphics: TikZ\n\ndoc = to_tikz(f⋅g)\nTikZ.pprint(doc)","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"EditURL = \"../../../literate/graphics/layouts_vs_drawings.jl\"","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/#Layouts-versus-drawings-of-wiring-diagrams","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"","category":"section"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"(Image: )","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"In Catlab, layout and drawing (rendering) of wiring diagrams are mostly decoupled. This notebook shows how to lay out diagrams using Graphviz's rank-based layout or Catlab's series-parallel layout and then render them using Compose.jl or TikZ.","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"The morphism we will visualize is:","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"using Catlab.Theories\n\nX = Ob(FreeSymmetricMonoidalCategory, :X)\nf, g, h = (Hom(sym, X, X) for sym in (:f, :g, :h))\n\nexpr = otimes(f, compose(f,g), compose(f,g,h))","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"Let's convert this expression into a wiring diagram. This yields a purely combinatorial object, as evidenced by its underlying graph.","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"using Catlab.WiringDiagrams, Catlab.Graphics\n\ndiagram = to_wiring_diagram(expr)\nWiringDiagrams.graph(diagram)","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/#Graphviz-layout","page":"Layouts versus drawings of wiring diagrams","title":"Graphviz layout","text":"","category":"section"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"Calling to_graphviz both lays out and draws the diagram, entirely within Graphviz.","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"to_graphviz(diagram, orientation=LeftToRight)","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"To get just the layout from Graphviz, we call graphviz_layout instead. We can then render this layout using Compose.jl. Note that the Graphviz layout has units in points.","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"import Compose\n\nlayout = graphviz_layout(diagram, orientation=LeftToRight)\nlayout_to_composejl(layout, base_unit=Compose.pt)","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"The same layout can be rendered in TikZ:","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"import TikzPictures\n\nlayout_to_tikz(layout, base_unit=\"1pt\")","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/#Series-parallel-layout","page":"Layouts versus drawings of wiring diagrams","title":"Series-parallel layout","text":"","category":"section"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"Catlab has its own layout system based on series-parallel decomposition. In this case, the layout exactly recovers the structure of the morphism expression created at the beginning.","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"layout = layout_diagram(FreeSymmetricMonoidalCategory, diagram,\n orientation=LeftToRight)\nlayout_to_composejl(layout)","category":"page"},{"location":"generated/graphics/layouts_vs_drawings/","page":"Layouts versus drawings of wiring diagrams","title":"Layouts versus drawings of wiring diagrams","text":"layout_to_tikz(layout)","category":"page"},{"location":"apis/programs/#programs","page":"Programs","title":"Programs","text":"","category":"section"},{"location":"apis/programs/","page":"Programs","title":"Programs","text":"The module Catlab.Programs provides domain-specific languages (DSLs) for constructing diagrams of various kinds. The DSLs, implemented as Julia macros, are based on the syntax of the Julia language but often interpret that syntax very differently from standard Julia programs. Conversely, this module offers preliminary support for generating Julia code from wiring diagrams.","category":"page"},{"location":"apis/programs/","page":"Programs","title":"Programs","text":"There are two major macros for constructing wiring diagrams:","category":"page"},{"location":"apis/programs/","page":"Programs","title":"Programs","text":"@program, for directed wiring diagrams (DWDs)\n@relation, for undirected wiring diagrams (UWDs)","category":"page"},{"location":"apis/programs/","page":"Programs","title":"Programs","text":"There is a family of related macros for constructing category-theoretic diagrams included in DataMigrations.jl.","category":"page"},{"location":"apis/programs/#API","page":"Programs","title":"API","text":"","category":"section"},{"location":"apis/programs/","page":"Programs","title":"Programs","text":"Modules = [\n Programs.GenerateJuliaPrograms,\n Programs.ParseJuliaPrograms,\n Programs.RelationalPrograms\n]\nPrivate = false","category":"page"},{"location":"apis/programs/#Catlab.Programs.GenerateJuliaPrograms","page":"Programs","title":"Catlab.Programs.GenerateJuliaPrograms","text":"Compile or evaluate morphisms as Julia programs.\n\n\n\n\n\n","category":"module"},{"location":"apis/programs/#Catlab.Programs.GenerateJuliaPrograms.Block","page":"Programs","title":"Catlab.Programs.GenerateJuliaPrograms.Block","text":"A block of Julia code with input and output variables.\n\n\n\n\n\n","category":"type"},{"location":"apis/programs/#Catlab.Programs.GenerateJuliaPrograms.CompileState","page":"Programs","title":"Catlab.Programs.GenerateJuliaPrograms.CompileState","text":"Internal state for compilation of morphism into Julia code.\n\n\n\n\n\n","category":"type"},{"location":"apis/programs/#Catlab.Programs.GenerateJuliaPrograms.compile_block-Tuple{HomExpr, Vector}","page":"Programs","title":"Catlab.Programs.GenerateJuliaPrograms.compile_block","text":"Compile a morphism expression into a block of Julia code.\n\n\n\n\n\n","category":"method"},{"location":"apis/programs/#Catlab.Programs.GenerateJuliaPrograms.compile_expr-Tuple{HomExpr}","page":"Programs","title":"Catlab.Programs.GenerateJuliaPrograms.compile_expr","text":"Compile a morphism expression into a Julia function expression.\n\n\n\n\n\n","category":"method"},{"location":"apis/programs/#Catlab.Programs.GenerateJuliaPrograms.evaluate-Tuple{HomExpr, Vararg{Any}}","page":"Programs","title":"Catlab.Programs.GenerateJuliaPrograms.evaluate","text":"Evaluate a morphism as a function.\n\nIf the morphism will be evaluated only once (possibly with vectorized inputs), then direct evaluation will be much faster than compiling (via compile) and evaluating a standard Julia function.\n\nCompare with functor.\n\n\n\n\n\n","category":"method"},{"location":"apis/programs/#GATlab.Syntax.GATs.compile-Tuple{Module, HomExpr}","page":"Programs","title":"GATlab.Syntax.GATs.compile","text":"Compile a morphism expression into a Julia function.\n\n\n\n\n\n","category":"method"},{"location":"apis/programs/#Catlab.Programs.ParseJuliaPrograms","page":"Programs","title":"Catlab.Programs.ParseJuliaPrograms","text":"Parse Julia programs into morphisms represented as wiring diagrams.\n\n\n\n\n\n","category":"module"},{"location":"apis/programs/#Catlab.Programs.ParseJuliaPrograms.parse_wiring_diagram-Tuple{Presentation, Expr}","page":"Programs","title":"Catlab.Programs.ParseJuliaPrograms.parse_wiring_diagram","text":"Parse a wiring diagram from a Julia function expression.\n\nFor more information, see the corresponding macro @program.\n\n\n\n\n\n","category":"method"},{"location":"apis/programs/#Catlab.Programs.ParseJuliaPrograms.@program-Tuple{Any, Vararg{Any}}","page":"Programs","title":"Catlab.Programs.ParseJuliaPrograms.@program","text":"Parse a wiring diagram from a Julia program.\n\nFor the most part, this is standard Julia code but a few liberties are taken with the syntax. Products are represented as tuples. So if x and y are variables of type X and Y, then (x,y) has type X Y. Also, both () and nothing are interpreted as the monoidal unit I.\n\nUnlike standard Julia, the function call expressions f(x,y) and f((x,y)) are equivalent. Consequently, given morphisms f W X Y and g X Y Z, the code\n\nx, y = f(w)\ng(x,y)\n\nis equivalent to g(f(w)). In standard Julia, at most one of these calls to g would be valid, unless g had multiple signatures.\n\nThe diagonals (copying and deleting) of a cartesian category are implicit in the Julia syntax: copying is variable reuse and deleting is variable non-use. For the codiagonals (merging and creating), a special syntax is provided, reinterpreting Julia's vector literals. The merging of x1 and x2 is represented by the vector [x1,x2] and creation by the empty vector []. For example, f([x1,x2]) translates to compose(mmerge(X),f).\n\nThis macro is a wrapper around parse_wiring_diagram.\n\n\n\n\n\n","category":"macro"},{"location":"apis/programs/#Catlab.Programs.RelationalPrograms","page":"Programs","title":"Catlab.Programs.RelationalPrograms","text":"Parse relation expressions in Julia syntax into undirected wiring diagrams.\n\n\n\n\n\n","category":"module"},{"location":"apis/programs/#Catlab.Programs.RelationalPrograms.RelationDiagram","page":"Programs","title":"Catlab.Programs.RelationalPrograms.RelationDiagram","text":"Abstract type for UWDs created by @relation macro.\n\n\n\n\n\n","category":"type"},{"location":"apis/programs/#Catlab.Programs.RelationalPrograms.TypedRelationDiagram","page":"Programs","title":"Catlab.Programs.RelationalPrograms.TypedRelationDiagram","text":"Typed UWD created by @relation macro.\n\n\n\n\n\n","category":"type"},{"location":"apis/programs/#Catlab.Programs.RelationalPrograms.UntypedRelationDiagram","page":"Programs","title":"Catlab.Programs.RelationalPrograms.UntypedRelationDiagram","text":"Untyped UWD created by @relation macro.\n\n\n\n\n\n","category":"type"},{"location":"apis/programs/#Catlab.Programs.RelationalPrograms.parse_relation_diagram-Tuple{Expr}","page":"Programs","title":"Catlab.Programs.RelationalPrograms.parse_relation_diagram","text":"Parse an undirected wiring diagram from a relation expression.\n\nFor more information, see the corresponding macro @relation.\n\n\n\n\n\n","category":"method"},{"location":"apis/programs/#Catlab.Programs.RelationalPrograms.@relation-Tuple","page":"Programs","title":"Catlab.Programs.RelationalPrograms.@relation","text":"Construct an undirected wiring diagram using relation notation.\n\nUnlike the @program macro for directed wiring diagrams, this macro departs significantly from the usual semantics of the Julia programming language. Function calls with n arguments are now interpreted as assertions that an n-ary relation holds at a particular point. For example, the composite of binary relations R X Y and S Y Z can be represented as an undirected wiring diagram by the macro call\n\n@relation (x,z) where (x::X, y::Y, z::Z) begin\n R(x,y)\n S(y,z)\nend\n\nIn general, the context in the where clause defines the set of junctions in the diagram and variable sharing defines the wiring of ports to junctions. If the where clause is omitted, the set of junctions is inferred from the variables used in the macro call.\n\nThe ports and junctions of the diagram may be typed or untyped, and the ports may be named or unnamed. Thus, four possible types of undirected wiring diagrams may be returned, with the type determined by the form of relation header:\n\nUntyped, unnamed: @relation (x,z) where (x,y,z) ...\nTyped, unnamed: @relation (x,z) where (x::X, y::Y, z::Z) ...\nUntyped, named: @relation (out1=x, out2=z) where (x,y,z) ...\nTyped, named: @relation (out=1, out2=z) where (x::X, y::Y, z::Z) ...\n\nAll four types of diagram are subtypes of RelationDiagram.\n\n\n\n\n\n","category":"macro"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"EditURL = \"../../../literate/wiring_diagrams/wiring_diagram_basics.jl\"","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#wiring_diagram_basics","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"(Image: )","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"using GATlab, you can create, manipulate, serialize, and visualize wiring diagrams, also known as string diagrams. The flexible data structure for wiring diagrams allows arbitrary data to be attached to boxes, ports, and wires, and supports recursively nested diagrams.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"You can interact with wiring diagrams using two different progamming interfaces:","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"Categorical: A high-level, functional interface expressed in terms of categorical concepts, such as composition (compose), monoidal products (otimes), duplication (mcopy), and deletion (delete).\nImperative: A lower-level, mutating interface to directly manipulate boxes, ports, and wires, via operations like adding boxes (add_box) and wires (add_wire).","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"In this notebook, we introduce both interfaces. We do not explicitly cover the visualization API, although for illustrative purposes we will draw wiring diagrams using Graphviz. Thus, you should install Graphviz if you wish to run this notebook.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"using Catlab.WiringDiagrams\n\nusing Catlab.Graphics\nimport Catlab.Graphics: Graphviz\n\nshow_diagram(d::WiringDiagram) = to_graphviz(d,\n orientation=LeftToRight,\n labels=true, label_attr=:xlabel,\n node_attrs=Graphviz.Attributes(\n :fontname => \"Courier\",\n ),\n edge_attrs=Graphviz.Attributes(\n :fontname => \"Courier\",\n )\n)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Data-structures","page":"Basics of wiring diagrams","title":"Data structures","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"The basic building blocks of a wiring diagram are boxes, ports, and wires. The top-level data structure is WiringDiagram, defined in the module Catlab.WiringDiagrams. A wiring diagram consists of boxes (usually of type Box) connected by wires (of type Wire). Each box has a sequence of input ports and a sequence of output ports, as does the wiring diagram itself. The wires have sources and targets, both of which consist of a box and a port on that box.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"The boxes in a wiring diagram are indexed by integer IDs. Boxes can be retrieved by ID, and wires refer to boxes using their IDs. Two special IDs, obtained by input_id and output_id methods, refer to the inputs and outputs of the diagram itself. In this way, wires can connect the (inner) boxes of a diagram to the diagram's \"outer box\".","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"The WiringDiagram data structure is an elaborate wrapper around a directed graph from Graphs.jl. The underlying DiGraph object can be accessed using the graph method. The vertices of this graph are exactly the box IDs. The graph should never be mutated directly, on pain of creating inconsistent state, but it does allow convenient access to the large array of graph algorithms supported by Graphs.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"All this is somewhat abstract but should become clearer as we see concrete examples.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Categorical-interface","page":"Basics of wiring diagrams","title":"Categorical interface","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"In this example, the wiring diagrams will carry symbolic expressions (of type Catlab.ObExpr and Catlab.HomExpr).","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"using Catlab.Theories\n\nA, B, C, D = Ob(FreeBiproductCategory, :A, :B, :C, :D)\nf = Hom(:f, A, B)\ng = Hom(:g, B, C)\nh = Hom(:h, C, D)\n\nf","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Generators","page":"Basics of wiring diagrams","title":"Generators","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"Convert each of the morphism generators into a diagram with a single box.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"f, g, h = to_wiring_diagram(f), to_wiring_diagram(g), to_wiring_diagram(h)\nf","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(f)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Composition","page":"Basics of wiring diagrams","title":"Composition","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"compose(f,g)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(compose(f,g))","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Monoidal-products","page":"Basics of wiring diagrams","title":"Monoidal products","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"otimes(f,h)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(otimes(f,h))","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Copy-and-merge,-delete-and-create","page":"Basics of wiring diagrams","title":"Copy and merge, delete and create","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"mcopy(codom(f),2)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(mcopy(codom(f),2))","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(compose(f, mcopy(codom(f),2)))","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(compose(mcopy(dom(f),2), otimes(f,f)))","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Imperative-interface","page":"Basics of wiring diagrams","title":"Imperative interface","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"We now show how to manipulate wiring diagrams using the low-level, imperative interface. The diagrams will carry Julia symbols.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"f = Box(:f, [:A], [:B])\ng = Box(:g, [:B], [:C])\nh = Box(:h, [:C], [:D])\n\nf","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Composition-2","page":"Basics of wiring diagrams","title":"Composition","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"For example, here is how to manually construct a composition of two boxes.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"The add_box! method adds a box to a wiring diagrams and returns the ID assigned to the box. How the boxes are indexed is an implementation detail that you should not rely on; use the IDs that the system gives you.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"d = WiringDiagram([:A], [:C])\n\nfv = add_box!(d, f)\ngv = add_box!(d, g)\n\nadd_wires!(d, [\n (input_id(d),1) => (fv,1),\n (fv,1) => (gv,1),\n (gv,1) => (output_id(d),1),\n])\n\nnboxes(d)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"nwires(d)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"d","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(d)","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/#Products","page":"Basics of wiring diagrams","title":"Products","text":"","category":"section"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"Here is how to manually construct a product of two boxes.","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"d = WiringDiagram([:A,:C], [:B,:D])\n\nfv = add_box!(d, f)\nhv = add_box!(d, h)\n\nadd_wires!(d, [\n (input_id(d),1) => (fv,1),\n (input_id(d),2) => (hv,1),\n (fv,1) => (output_id(d),1),\n (hv,1) => (output_id(d),2),\n])\n\nd","category":"page"},{"location":"generated/wiring_diagrams/wiring_diagram_basics/","page":"Basics of wiring diagrams","title":"Basics of wiring diagrams","text":"show_diagram(d)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"EditURL = \"../../../literate/graphs/graphs.jl\"","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"using GATlab, Catlab.Theories\nusing Catlab.CategoricalAlgebra\nusing Catlab.Graphs\nusing Catlab.Graphics\n\ndraw(g; kw...) = to_graphviz(g; node_labels=true, edge_labels=true, kw...)\ndraw(f::ACSetTransformation; kw...) =\n to_graphviz(f; node_labels=true, edge_labels=true, draw_codom=false, kw...)\n\nto_graphviz(SchGraph)","category":"page"},{"location":"generated/graphs/graphs/#The-Category-of-Graphs","page":"The Category of Graphs","title":"The Category of Graphs","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"The Theory of Graphs is given by the following Schema:","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"@present SchGraph(FreeSchema) begin\n V::Ob\n E::Ob\n src::Hom(E,V)\n tgt::Hom(E,V)\nend\n\n\"\"\" Abstract type for graphs, aka directed multigraphs.\n\"\"\"\n@abstract_acset_type AbstractGraph <: HasGraph\n\n\"\"\" A graph, also known as a directed multigraph.\n\"\"\"\n@acset_type Graph(SchGraph, index=[:src,:tgt]) <: AbstractGraph","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"That is all we need to do to generate the functor category [SchGraph, FinSet]. Catlab knows how to take a finitely presented category and generate all the data structures that you need to represent functors into FinSet and natural transformations between those functors. Note: the index=[:src, :tgt] keyword argument tells Catlab that you want to have an efficient index the preimages of those morphisms. in this example, we want to be able to find the incoming and outgoing edges of a vertex in O(1) time.","category":"page"},{"location":"generated/graphs/graphs/#Creating-some-Graphs","page":"The Category of Graphs","title":"Creating some Graphs","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Once you have fixed the schema (aka indexing category or theory), you can make some instances. Catlab has a DSL for specifying instances of any schema. It is called @acset. In order to specify a Functor F=(F₀, F₁) into FinSet, you need to provide some data. 1. For every A:Ob(C), you need F₀(A):FinSet 2. For every f:A→B, you need to specify a FinFunction F₁(f):F₀(A)→F₀(B) If the theory C has some equations, the data you provide would have to also satisfy those equations. The theory of graphs has no equations, so there are no constraints on the data you provide, except for those that come from functoriality.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"e = @acset Graph begin\n V = 2\n E = 1\n src = [1]\n tgt = [2]\nend\n\ndraw(e)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"a wedge is two edges that share a target","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"w = @acset Graph begin\n V = 3\n E = 2\n src=[1,3]\n tgt=[2,2]\nend\n\ndraw(w)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"The CSet API generalizes the traditional Graph API","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"parts(w, :V) # vertex set\n\nparts(w,:E) # edge set\n\nw[:src] # source map\n\nw[:tgt] # target map\n\n\nincident(w, 1, :src) # edges out of vertex 1\n\nincident(w, 2, :tgt) # edges into vertex 2\n\nw[incident(w, 2, :tgt), :src] # vertices that are the source of edges whose target is vertex 2\n\nw[incident(w, 1, :src), :tgt] # vertices that are the target of edges whose src is vertex 1","category":"page"},{"location":"generated/graphs/graphs/#Exercise:","page":"The Category of Graphs","title":"Exercise:","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Use the @acset macro to make a graph with at least 5 vertices\nDraw the graph\nCompute in neighbors and out neighbors and make sure they match your expectations.\nWrite a function that computes the 2-hop out-neighbors of a vertex.","category":"page"},{"location":"generated/graphs/graphs/#Graph-Homomorphisms","page":"The Category of Graphs","title":"Graph Homomorphisms","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"We can construct some graph homomorphisms between our two graphs. What data do we need to specify?","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ = ACSetTransformation(e,w,E=[1], V=[1,2])\n\nis_natural(ϕ)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"The ACSetTransformation constructor does not automatically validate that the naturality squares commute!","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕᵦ = ACSetTransformation(e,w,E=[1], V=[3,2])\nis_natural(ϕᵦ)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Our ϕᵦ in't natural because the edge map e₁ ↦ e₁ is not consistent with our vertex map, which sends v₁ ↦ v₃ and v₂ ↦ v₂. We can fix this by sending e₁ to e₂","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕᵦ′ = ACSetTransformation(e,w,E=[2], V=[3,2])\nis_natural(ϕᵦ′)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"So how does Catlab store the data of the natural transformation? the domain","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ.dom","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"the codomain","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ.codom","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"the components","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ.components","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"you can see the components using standard indexing notation with the object names. Notice that while CSets are indexed by morphisms, natural transformations are indexed by objects.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ[:V]\nϕ[:E]","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"We can check the naturality squares ourselves The sources are preserved: src ⋅ ϕᵥ == ϕₑ ⋅ src","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ[:V](dom(ϕ)[:,:src]) == codom(ϕ)[collect(ϕ[:E]), :src]","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"The targets are preserved: tgt ⋅ ϕᵥ == ϕₑ ⋅ tgt","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"ϕ[:V](dom(ϕ)[:,:tgt]) == codom(ϕ)[collect(ϕ[:E]), :tgt]","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"This approach generalizes to the following:","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"function is_natural(α::ACSetTransformation{S}) where {S}\n X, Y = dom(α), codom(α)\n for (f, c, d) in zip(hom(S), dom(S), codom(S))\n Xf, Yf, α_c, α_d = subpart(X,f), subpart(Y,f), α[c], α[d]\n all(Yf[α_c(i)] == α_d(Xf[i]) for i in eachindex(Xf)) || return false\n end\n return true\nend","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Notice how we iterate over the homs in the schema category S (f, c, d) in zip(hom(S), dom(S), codom(S)) We get one universally quantified equation all(Yf[α_c(i)] == α_d(Xf[i]) for i in eachindex(Xf)) for each morphism in the indexing category","category":"page"},{"location":"generated/graphs/graphs/#Exercise:-2","page":"The Category of Graphs","title":"Exercise:","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Take your graph from the previous exercise and construct a graph homomorphism from the wedge (w) into it.\nCheck that the naturality equations are satisfied.\nExplain why we don't need to specify any data for the source and target morphisms in SchGraph when definining a graph homomorphism","category":"page"},{"location":"generated/graphs/graphs/#Finding-Homomorphisms-Automatically","page":"The Category of Graphs","title":"Finding Homomorphisms Automatically","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"As you saw in the previous exercise, constructing a natural transformation can be quite tedious. We want computers to automate tedious things for us. So we use an algorithm to enumerate all the homomorphisms between two CSets.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"CSet homomorphisms f:A→B are ways of finding a part of B that is shaped like A. You can view this as pattern matching. The graph A is the pattern and the graph B is the data. A morphism f:A→B is a collection of vertices and edges in B that is shaped like A. Note that you can ask Catlab to enforce constraints on the homomorphisms it will find including computing monic (injective) morphisms by passing the keyword monic=true. A monic morphism into B is a subobject of B. You can pass iso=true to get isomorphisms.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"t = @acset Graph begin\n V = 3\n E = 3\n src = [1,2,1]\n tgt = [2,3,3]\nend\n\ndraw(t)\n\nT = @acset Graph begin\n V = 6\n E = 9\n src = [1,2,1, 3, 1,5,2,2,4]\n tgt = [2,3,3, 4, 4,6,5,6,6]\nend\n\ndraw(T)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"The simplest pattern in a graph is just a single edge and each homomorphism ϕ:e→G is a single edge in G.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"length(homomorphisms(e, T, monic=true)) == nparts(T,:E) # number of edges\n\n\nlength(homomorphisms(t, T))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"We can define this helper function to print out all the homomorphisms between graphs. Because all our graphs are simple, we only need to look at the vertex components.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"graphhoms(g,h) = begin\n map(homomorphisms(g,h)) do ϕ\n collect(ϕ[:V])\n end\nend\n\ngraphhoms(t, T)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Homs ϕ:t→T are little triangles in T, but homs ϕ:T→t are colorings of T with 3 colors. The fact that there are edges in t that are missing, means that it provides constraints on what graphs have morphisms into it. For example, there are no morphisms T→t.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"graphhoms(T, t)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"The reason we don't have a morphism into t is vertices 2,3,4,5 aren't arranged into a triangle. We can relax those constraints by adding loops to the codomain. Loops in the codomain allow you to merge adjacent vertices when you construct the homomorphism.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"add_loops!(g) = add_parts!(g, :E, nparts(g,:V), src=parts(g,:V), tgt=parts(g,:V))\nadd_loops(g) = begin\n h = copy(g)\n add_loops!(h)\n return h\nend\n\ndraw(add_loops(t))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Once we add loops, then we have morphisms.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"length(homomorphisms(T,add_loops(t)))","category":"page"},{"location":"generated/graphs/graphs/#Bipartite-Graphs","page":"The Category of Graphs","title":"Bipartite Graphs","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Many computer science problems involve graphs that have two types of vertices. For example, when matching students to classes, you might represent the students as one type of vertex and the classes as another type of vertex. Then the edges (s,c) represent \"student s is enrolled in class c\". In this scenario there can be no edges from a class vertex to another class vertex, or from a student vertex to a student vertex. Graphs for which there exists such a classification are called bipartite graphs. In Category Theory, we shift from thinking about graphs with properties to graph homomorphisms that witness that property and think of bipartitioned graphs.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"First we construct a bipartite graph:","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"sq = apex(product(add_loops(e), add_loops(e)))\nrem_parts!(sq, :E, [1,5,6,8,9])\ndraw(sq)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"We will use the symmetric edge graph to identify the bipartitions of this graph.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"esym = @acset Graph begin\n V = 2\n E = 2\n src = [1,2]\n tgt = [2,1]\nend\n\ndraw(id(esym))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"There are two ways to bipartition sq.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"graphhoms(sq, esym)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"This comes from the fact that esym has 2 automorphisms!","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"graphhoms(esym, esym)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"the first coloring","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"draw(homomorphisms(sq, esym)[1])","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"but we can also swap the roles of the colors","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"draw(homomorphisms(sq, esym)[2])","category":"page"},{"location":"generated/graphs/graphs/#Exercise:-3","page":"The Category of Graphs","title":"Exercise:","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Construct a graph representation of a checkerboard\nDraw the two bipartitions of the checkerboard","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"We can generalize the notion of Bipartite graph to any number of parts. I like to call Kₖ the k-coloring classifier because homomorphims into α:G → Kₖ are k-colorings of G.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"clique(k::Int) = begin\n Kₖ = Graph(k)\n for i in 1:k\n for j in 1:k\n if j ≠ i\n add_parts!(Kₖ, :E, 1, src=i, tgt=j)\n end\n end\n end\n return Kₖ\nend\n\nK₃ = clique(3)\ndraw(id(K₃))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Our graph T is not 2-colorable,","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"length(homomorphisms(T, esym))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"but we can use 3 colors to color T.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"draw(homomorphism(T, K₃))","category":"page"},{"location":"generated/graphs/graphs/#Exercise:-4","page":"The Category of Graphs","title":"Exercise:","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Find a graph that is not 3-colorable\nFind a graph that is not 4-colorable","category":"page"},{"location":"generated/graphs/graphs/#Homomorphisms-in-[C,-Set]-are-like-Types","page":"The Category of Graphs","title":"Homomorphisms in [C, Set] are like Types","text":"","category":"section"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Any graph can play the role of the codomain. If you pick a graph that is incomplete, you get a more constrained notion of coloring where there are color combinations that are forbidden.","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"triloop = @acset Graph begin\n V = 3\n E = 3\n src = [1,2,3]\n tgt = [2,3,1]\nend\n\ndraw(id(triloop))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"With this graph, we can pick out directed 3-cycles in a graph like T2,","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"T2 = @acset Graph begin\n V = 6\n E = 6\n src = [1,2,3,4,5,6]\n tgt = [2,3,1,5,6,4]\nend\ngraphhoms(T2, triloop)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"and we can draw those cyclic roles with colors","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"draw(homomorphisms(T2, triloop)[1])\n\nT3 = @acset Graph begin\n V = 6\n E = 7\n src = [1,2,3,4,5,6, 2]\n tgt = [2,3,1,5,6,4, 4]\nend\ngraphhoms(T3, triloop)","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"Using the colors as shown:","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"draw(id(triloop))","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"We can see our coloring of T3:","category":"page"},{"location":"generated/graphs/graphs/","page":"The Category of Graphs","title":"The Category of Graphs","text":"draw(homomorphisms(T3, triloop)[1])","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"EditURL = \"../../../literate/sketches/meets.jl\"","category":"page"},{"location":"generated/sketches/meets/#Meets-in-Preorders","page":"Meets in Preorders","title":"Meets in Preorders","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"(Image: )","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Our first example of a concept defined by a universal mapping property is a meet respectively meet.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"The first step is our Catlab imports","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"using Core: GeneratedFunctionStub\nusing Test\n\nusing Catlab.Theories, Catlab.CategoricalAlgebra, Catlab.Graphics\nimport Catlab.Theories: compose\n\nusing DataStructures","category":"page"},{"location":"generated/sketches/meets/#Defining-some-basic-preorders","page":"Meets in Preorders","title":"Defining some basic preorders","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"@present P(FreeSchema) begin\n (a₁,a₂,a₃,a₄)::Ob\n f::Hom(a₁, a₂)\n g::Hom(a₁, a₃)\n h::Hom(a₂, a₄)\n k::Hom(a₃, a₄)\nend","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"We can draw a picture of our preorder as a Hasse Diagram.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"to_graphviz(P)","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"It will be convenient to program with our preorders based on the Hasse Diagram represent as a labeled graph so we convert the Presentation{Schema, Symbol} into a FreeDigram. FreeDiagrams are implemented as an ACSet which you can think of as an in-memory database. ACSets are a key feature of Catlab that allow you to represent many data structures in a common framework.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"g = FreeDiagram(P)","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"To give ourselves a graph-like API for Hasse Diagrams, we define parents and children.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"parents(g, y::Int) = subpart(g, incident(g, y, :tgt), :src)\nchildren(g, x::Int) = subpart(g, incident(g, x, :src), :tgt)","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"We can compute upsets/downsets with breadth first search.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"function bfs(g, x::Int, f=children)\n explored = falses(nparts(g, :V))\n explored[x] = 1\n q = Queue{Int}()\n enqueue!(q, x)\n while !isempty(q)\n v = dequeue!(q)\n S = f(g,v)\n map(filter(s -> !explored[s], S)) do s\n enqueue!(q, s)\n end\n explored[S] .= true\n end\n return findall(explored)\nend","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"The upset of a preorder element is all the elements that come after it in the preorder.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"upset(g,x) = bfs(g,x,children)","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"The downset is the dual notion, which we compute by reversing the role of children and parents.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"downset(g,x) = bfs(g,x,parents)\n\nupset(g, 1)","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"We can use upsets to define the less than or equal two relation implied by any Hasse Diagram","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"function leq(g::FreeDiagram, x::Int, y::Int)\n return y in upset(g, x)\nend","category":"page"},{"location":"generated/sketches/meets/#Exercise-1","page":"Meets in Preorders","title":"Exercise 1","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Define a more efficient algorithm for checking whether two elements satisfy the leq relation.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Multiple dispatch allows us to overload the leq function with another method for symbols.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"function leq(g::FreeDiagram, x::Symbol, y::Symbol)\n leq(g, incident(g, x, :ob), incident(g, y, :ob))\nend","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"the meet of two elements is the largest element in the intersection of their downsets.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"function meet(g::FreeDiagram, x::Int, y::Int)\n U = downset(g, x) ∩ downset(g,y)\n maxima(g, U)\n return maximum(g, U)\nend\n\nfunction meet(g::FreeDiagram, x, y)\n meet(g, incident(g, x, :ob)[1], incident(g, y, :ob)[1])\nend","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"assuming that D is a downset, the maxima are those elements whose children are disjoint from D.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"function maxima(g::FreeDiagram, D::Vector{Int})\n X = Set(D)\n M = filter(D) do x\n Pₓ = children(g, x) ∩ X\n length(Pₓ) == 0\n end\n return M\nend\n\nfunction hastop(g::FreeDiagram, xs::Vector{Int})\n length(maxima(g, xs)) == 1\nend\n\nfunction maximum(g::FreeDiagram, xs::Vector{Int})\n m = maxima(g, xs::Vector{Int})\n if length(m) == 1\n return m[1]\n end\n if length(m) > 1\n all_iso = all(m) do a\n Uₐ = downset(g, a)\n a_le_allb = all(m) do b\n b in Uₐ\n end\n return a_le_allb\n end\n if all_iso\n return m[1]\n end\n end\n return nothing\nend","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"From the definition of minimum, you can see that when you want to do many leq queries in sequence, you can reuse the upsets that you compute with bfs. This is a place where mathematical abstractions don't work well with the operational needs of computer programming. In a mathematical definition you can define x ≤ y as y ∈ upset(x), but in programming, that is inefficient when you want to check a property like for all y in Y, x ≤ y. Programming requires you to reason about not only the correctness of the code, but also the performance. Much of the complexity of software engineering comes from the fact that computational performance requires the programmers to break down their clean abstractions to optimize the code.","category":"page"},{"location":"generated/sketches/meets/#Exercise-2","page":"Meets in Preorders","title":"Exercise 2","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"If you wanted to perform many x ≤ y queries in a loop, you might want to precompute the matrix L where L[i,j] = 1 if and only if i ≤ j in the preorder P. Implement an algorithm that performs this computation in O(V⋅E) time where V is the number of elements in P and E is the number of edges in the corresponding FreeDiagram.","category":"page"},{"location":"generated/sketches/meets/#Testing-it-out","page":"Meets in Preorders","title":"Testing it out","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Let's make sure we get the answers that we expect.","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"using Test\n@testset \"Upsets\" begin\n @test upset(g, 3) == [3,4]\n @test upset(g, 2) == [2,4]\n @test upset(g, 1) == [1,2,3,4]\n @test upset(g, 4) == [4]\nend\n@testset \"Downsets\" begin\n @test downset(g, 3) == [1,3]\n @test downset(g, 2) == [1,2]\n @test downset(g, 4) == [1,2,3,4]\n @test downset(g, 1) == [1]\nend\n\n@testset \"Meets\" begin\n @test meet(g, 2,3) == 1\n @test meet(g, 1,2) == 1\n @test meet(g, 3,4) == 3\n @test meet(g, 1, 4) == 1\n @test meet(g, 1, 1) == 1\n @test meet(g, 2, 2) == 2\nend","category":"page"},{"location":"generated/sketches/meets/#Another-Example:","page":"Meets in Preorders","title":"Another Example:","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"@present P(FreeSchema) begin\n (a₁,a₂,a₃,a₄, a₅)::Ob\n f::Hom(a₁, a₂)\n g::Hom(a₁, a₃)\n h::Hom(a₂, a₄)\n k::Hom(a₃, a₄)\n l::Hom(a₅, a₂)\nend","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Which can be viewed as a picture:","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"to_graphviz(P)","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Or, as tables:","category":"page"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"g = FreeDiagram(P)","category":"page"},{"location":"generated/sketches/meets/#Test-suite","page":"Meets in Preorders","title":"Test suite","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"@testset \"meets2\" begin\n @test meet(g, 2,3) == 1\n @test meet(g, 1,2) == 1\n @test meet(g, 3,4) == 3\n @test meet(g, 1, 4) == 1\n @test meet(g, 1, 1) == 1\n @test meet(g, 2, 2) == 2\n @test meet(g, 3, 5) == nothing\n @test meet(g, 2, 5) == 5\nend","category":"page"},{"location":"generated/sketches/meets/#Exercise-3","page":"Meets in Preorders","title":"Exercise 3","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Make bigger preorders to test corner cases in the above code. If you find an example that breaks these implementations, please report it.","category":"page"},{"location":"generated/sketches/meets/#Exercise-4","page":"Meets in Preorders","title":"Exercise 4","text":"","category":"section"},{"location":"generated/sketches/meets/","page":"Meets in Preorders","title":"Meets in Preorders","text":"Implement the dual constructions for joins.","category":"page"},{"location":"apis/graphs/#graphs","page":"Graphs","title":"Graphs","text":"","category":"section"},{"location":"apis/graphs/","page":"Graphs","title":"Graphs","text":"Modules = [\n Graphs.BasicGraphs,\n Graphs.BipartiteGraphs,\n Graphs.NamedGraphs,\n Graphs.PropertyGraphs,\n Graphs.GraphAlgorithms,\n Graphs.GraphGenerators,\n]\nPrivate = false","category":"page"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs","page":"Graphs","title":"Catlab.Graphs.BasicGraphs","text":"Data structures for graphs, based on C-sets.\n\nThis module provides the category theorist's four basic kinds of graphs: graphs (aka directed multigraphs), symmetric graphs, reflexive graphs, and symmetric reflexive graphs. It also defines half-edge graphs, which are isomorphic to symmetric graphs, and a few standard kinds of attributed graphs, such as weighted graphs.\n\nThe graphs API generally follows that of Graphs.jl, with some departures due to differences between the data structures.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractGraph","text":"Abstract type for graphs, aka directed multigraphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractHalfEdgeGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractHalfEdgeGraph","text":"Abstract type for half-edge graphs, possibly with data attributes.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractLabeledGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractLabeledGraph","text":"Abstract type for labeled graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractReflexiveGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractReflexiveGraph","text":"Abstract type for reflexive graphs, possibly with data attributes.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractSymmetricGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractSymmetricGraph","text":"Abstract type for symmetric graph, possibly with data attributes.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractSymmetricReflexiveGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractSymmetricReflexiveGraph","text":"Abstract type for symmetric reflexive graphs, possibly with data attributes.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractSymmetricWeightedGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractSymmetricWeightedGraph","text":"Abstract type for symmetric weighted graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.AbstractWeightedGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.AbstractWeightedGraph","text":"Abstract type for weighted graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.Graph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.Graph","text":"A graph, also known as a directed multigraph.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.HalfEdgeGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.HalfEdgeGraph","text":"A half-edge graph.\n\nHalf-edge graphs are a variant of undirected graphs whose edges are pairs of \"half-edges\" or \"darts\". Half-edge graphs are isomorphic to symmetric graphs but have a different data model.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.HasGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.HasGraph","text":"Abstract type for C-sets that contain a graph.\n\nThis type encompasses C-sets where the schema for graphs is a subcategory of C. This includes, for example, graphs, symmetric graphs, and reflexive graphs, but not half-edge graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.HasVertices","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.HasVertices","text":"Abstract type for C-sets that contain vertices.\n\nThis type encompasses C-sets where the schema C contains an object V interpreted as vertices. This includes, for example, graphs and half-edge graphs, but not bipartite graphs or wiring diagrams.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.LabeledGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.LabeledGraph","text":"A labeled graph.\n\nBy convention, a \"labeled graph\" without qualification is a vertex-labeled graph. We do not require that the label be unique, and in this data type, the label attribute is not indexed.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.ReflexiveGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.ReflexiveGraph","text":"A reflexive graph.\n\nReflexive graphs are graphs in which every vertex has a distinguished self-loop.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.SymmetricGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.SymmetricGraph","text":"A symmetric graph, or graph with an orientation-reversing edge involution.\n\nSymmetric graphs are closely related, but not identical, to undirected graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.SymmetricReflexiveGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.SymmetricReflexiveGraph","text":"A symmetric reflexive graph.\n\nSymmetric reflexive graphs are both symmetric graphs (SymmetricGraph) and reflexive graphs (ReflexiveGraph) such that the reflexive loops are fixed by the edge involution.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.SymmetricWeightedGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.SymmetricWeightedGraph","text":"A symmetric weighted graph.\n\nA symmetric graph in which every edge has a numerical weight, preserved by the edge involution.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.WeightedGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.WeightedGraph","text":"A weighted graph.\n\nA graph in which every edge has a numerical weight.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Base.inv-Tuple{AbstractHalfEdgeGraph, Vararg{Any}}","page":"Graphs","title":"Base.inv","text":"Involution on half-edge(s) in a half-edge graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Base.inv-Tuple{HasGraph, Vararg{Any}}","page":"Graphs","title":"Base.inv","text":"Involution on edge(s) in a symmetric graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_dangling_edge!-Tuple{AbstractHalfEdgeGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_dangling_edge!","text":"Add a dangling edge to a half-edge graph.\n\nA \"dangling edge\" is a half-edge that is paired with itself under the half-edge involution. They are usually interpreted differently than \"self-loops\", i.e., a pair of distinct half-edges incident to the same vertex.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_dangling_edges!-Tuple{AbstractHalfEdgeGraph, AbstractVector{Int64}}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_dangling_edges!","text":"Add multiple dangling edges to a half-edge graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_edge!-Tuple{HasGraph, Int64, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_edge!","text":"Add an edge to a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_edges!-Tuple{HasGraph, AbstractVector{Int64}, AbstractVector{Int64}}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_edges!","text":"Add multiple edges to a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_vertex!-Tuple{HasVertices}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_vertex!","text":"Add a vertex to a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_vertices!-Tuple{HasVertices, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_vertices!","text":"Add multiple vertices to a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.add_vertices_with_indices!-Tuple{HasVertices, Int64, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.add_vertices_with_indices!","text":"Add vertices with preallocated src/tgt indexes\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.all_neighbors-Tuple{AbstractGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.all_neighbors","text":"Union of in-neighbors and out-neighbors in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.degree-Tuple{Any, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.degree","text":"Total degree of a vertex\n\nEquivalent to length(all_neighbors(g,v)) but faster\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.edges-Tuple{HasGraph}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.edges","text":"Edges in a graph, or between two vertices in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.half_edges-Tuple{AbstractHalfEdgeGraph}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.half_edges","text":"Half-edges in a half-edge graph, or incident to a vertex.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.has_edge-Tuple{HasGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.has_edge","text":"Whether the graph has the given edge, or an edge between two vertices.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.has_vertex-Tuple{HasVertices, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.has_vertex","text":"Whether the graph has the given vertex.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.induced_subgraph-Union{Tuple{G}, Tuple{G, AbstractVector{Int64}}} where G<:HasGraph","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.induced_subgraph","text":"Subgraph induced by a set of a vertices.\n\nThe induced subgraph consists of the given vertices and all edges between vertices in this set.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.inedges-Tuple{HasGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.inedges","text":"Edges coming into a vertex\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.inneighbors-Tuple{AbstractGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.inneighbors","text":"In-neighbors of vertex in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.ne-Tuple{HasGraph}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.ne","text":"Number of edges in a graph, or between two vertices in a graph.\n\nIn a symmetric graph, this function counts both edges in each edge pair, so that the number of edges in a symmetric graph is twice the number of edges in the corresponding undirected graph (at least when the edge involution has no fixed points).\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.neighbors-Tuple{AbstractGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.neighbors","text":"Neighbors of vertex in a graph.\n\nIn a graph, this function is an alias for outneighbors; in a symmetric graph, a vertex has the same out-neighbors and as in-neighbors, so the distinction is moot.\n\nIn the presence of multiple edges, neighboring vertices are given with multiplicity. To get the unique neighbors, call unique(neighbors(g)).\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.nv-Tuple{HasVertices}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.nv","text":"Number of vertices in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.outedges-Tuple{HasGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.outedges","text":"Edges coming out of a vertex\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.outneighbors-Tuple{AbstractGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.outneighbors","text":"Out-neighbors of vertex in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.refl-Tuple{HasGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.refl","text":"Reflexive loop(s) of vertex (vertices) in a reflexive graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.rem_edge!-Tuple{HasGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.rem_edge!","text":"Remove an edge from a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.rem_edges!-Tuple{HasGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.rem_edges!","text":"Remove multiple edges from a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.rem_vertex!-Tuple{HasVertices, Int64}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.rem_vertex!","text":"Remove a vertex from a graph.\n\nWhen keep_edges is false (the default), all edges incident to the vertex are also deleted. When keep_edges is true, incident edges are preserved but their source/target vertices become undefined.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.rem_vertices!-Tuple{AbstractGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.rem_vertices!","text":"Remove multiple vertices from a graph.\n\nEdges incident to any of the vertices are treated as in rem_vertex!.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.vertex-Tuple{AbstractHalfEdgeGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.vertex","text":"Incident vertex (vertices) of half-edge(s) in a half-edge graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.vertices-Tuple{HasVertices}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.vertices","text":"Vertices in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BasicGraphs.weight-Tuple{HasGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BasicGraphs.weight","text":"Weight(s) of edge(s) in a weighted graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Theories.src-Tuple{HasGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Theories.src","text":"Source vertex (vertices) of edges(s) in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Theories.tgt-Tuple{HasGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Theories.tgt","text":"Target vertex (vertices) of edges(s) in a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs","text":"Bipartite graphs, directed and undirected, as C-sets.\n\nA graph theorist might call these \"bipartitioned graphs,\" as in a graph equipped with a bipartition, as opposed to \"bipartite graphs,\" as in a graph that can be bipartitioned. Here we use the former notion, which is more natural from the structuralist perspective, but the latter terminology, which is shorter and more familiar.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.AbstractBipartiteGraph","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.AbstractBipartiteGraph","text":"Abstract type for bipartite graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.AbstractUndirectedBipartiteGraph","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.AbstractUndirectedBipartiteGraph","text":"Abstract type for undirected bipartite graphs.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.BipartiteGraph","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.BipartiteGraph","text":"A bipartite graph, better known as a bipartite directed multigraph.\n\nDirected bipartite graphs are isomorphic to port hypergraphs and to whole grain Petri nets.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.HasBipartiteGraph","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.HasBipartiteGraph","text":"Abstract type for C-sets that contain a (directed) bipartite graph.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.HasBipartiteVertices","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.HasBipartiteVertices","text":"Abstract type for C-sets that contain a bipartition of vertices.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.UndirectedBipartiteGraph","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.UndirectedBipartiteGraph","text":"An undirected bipartite graph.\n\nIt is a matter of perspective whether to consider such graphs \"undirected,\" in the sense that the edges have no orientation, or \"unidirected,\" in the sense that all edges go from vertices of type 1 to vertices of type 2.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_edges₁₂!-Tuple{HasBipartiteGraph, AbstractVector{Int64}, AbstractVector{Int64}}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_edges₁₂!","text":"Add edges from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_edges₂₁!-Tuple{HasBipartiteGraph, AbstractVector{Int64}, AbstractVector{Int64}}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_edges₂₁!","text":"Add edges from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_edge₁₂!-Tuple{HasBipartiteGraph, Int64, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_edge₁₂!","text":"Add edge from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_edge₂₁!-Tuple{HasBipartiteGraph, Int64, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_edge₂₁!","text":"Add edge from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_vertex₁!-Tuple{HasBipartiteVertices}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_vertex₁!","text":"Add a vertex of type 1 to a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_vertex₂!-Tuple{HasBipartiteVertices}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_vertex₂!","text":"Add a vertex of type 2 to a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_vertices₁!-Tuple{HasBipartiteVertices, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_vertices₁!","text":"Add vertices of type 1 to a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.add_vertices₂!-Tuple{HasBipartiteVertices, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.add_vertices₂!","text":"Add vertices of type 2 to a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.edges₁₂-Tuple{HasBipartiteGraph}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.edges₁₂","text":"Edges from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.edges₂₁-Tuple{HasBipartiteGraph}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.edges₂₁","text":"Edges from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.ne₁₂-Tuple{HasBipartiteGraph}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.ne₁₂","text":"Number of edges from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.ne₂₁-Tuple{HasBipartiteGraph}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.ne₂₁","text":"Number of edges from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.nv₁-Tuple{HasBipartiteVertices}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.nv₁","text":"Number of vertices of type 1 in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.nv₂-Tuple{HasBipartiteVertices}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.nv₂","text":"Number of vertices of type 2 in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_edges₁₂!-Tuple{AbstractBipartiteGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_edges₁₂!","text":"Remove edges from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_edges₂₁!-Tuple{AbstractBipartiteGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_edges₂₁!","text":"Remove edges from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_edge₁₂!-Tuple{AbstractBipartiteGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_edge₁₂!","text":"Remove edge from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_edge₂₁!-Tuple{AbstractBipartiteGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_edge₂₁!","text":"Remove edge from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_vertex₁!-Tuple{HasBipartiteVertices, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_vertex₁!","text":"Remove vertex of type 1 from a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_vertex₂!-Tuple{HasBipartiteVertices, Int64}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_vertex₂!","text":"Remove vertex of type 2 from a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_vertices₁!-Tuple{AbstractUndirectedBipartiteGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_vertices₁!","text":"Remove vertices of type 1 from a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.rem_vertices₂!-Tuple{AbstractUndirectedBipartiteGraph, Any}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.rem_vertices₂!","text":"Remove vertices of type 2 from a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.src₁-Tuple{HasBipartiteGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.src₁","text":"Source vertex of edge from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.src₂-Tuple{HasBipartiteGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.src₂","text":"Source vertex of edge from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.tgt₁-Tuple{HasBipartiteGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.tgt₁","text":"Target vertex of edge from V₂ to V₁ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.tgt₂-Tuple{HasBipartiteGraph, Vararg{Any}}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.tgt₂","text":"Target vertex of edge from V₁ to V₂ in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.vertices₁-Tuple{HasBipartiteVertices}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.vertices₁","text":"Vertices of type 1 in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.BipartiteGraphs.vertices₂-Tuple{HasBipartiteVertices}","page":"Graphs","title":"Catlab.Graphs.BipartiteGraphs.vertices₂","text":"Vertices of type 2 in a bipartite graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs","page":"Graphs","title":"Catlab.Graphs.NamedGraphs","text":"Extends the basic graph types with vertex and/or edge names.\n\nNaming vertices and edges and looking them up by name is a common requirement. This module provides a simple interface and default graph types for named graphs. Names are understood to be unique within the graph but are not assumed to be strings or symbols.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.AbstractNamedGraph","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.AbstractNamedGraph","text":"Abstract type for graph with named vertices and edges.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.NamedGraph","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.NamedGraph","text":"Graph with named vertices and edges.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.edge_name-Tuple{HasGraph, Any}","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.edge_name","text":"Name of an edge in a graph.\n\nBy default, the name of an edge is its ID.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.edge_named-Tuple{HasGraph, Any}","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.edge_named","text":"Get edge in graph with given name.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.has_edge_names-Tuple{T} where T<:HasGraph","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.has_edge_names","text":"Whether a graph has edge names distinct from its edge IDs.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.has_vertex_names-Tuple{T} where T<:HasVertices","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.has_vertex_names","text":"Whether a graph has vertex names distinct from its vertex IDs.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.vertex_name-Tuple{HasVertices, Any}","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.vertex_name","text":"Name of a vertex in a graph.\n\nBy default, the name of a vertex is its ID.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.NamedGraphs.vertex_named-Tuple{HasVertices, Any}","page":"Graphs","title":"Catlab.Graphs.NamedGraphs.vertex_named","text":"Get vertex in graph with given name.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.AbstractPropertyGraph","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.AbstractPropertyGraph","text":"Abstract type for graph with properties.\n\nConcrete types are PropertyGraph and SymmetricPropertyGraph.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.PropertyGraph","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.PropertyGraph","text":"Graph with properties.\n\n\"Property graphs\" are graphs with arbitrary named properties on the graph, vertices, and edges. They are intended for applications with a large number of ad-hoc properties. If you have a small number of known properties, it is better and more efficient to create a specialized C-set type using @acset_type.\n\nSee also: SymmetricPropertyGraph.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.SymmetricPropertyGraph","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.SymmetricPropertyGraph","text":"Symmetric graphs with properties.\n\nThe edge properties are preserved under the edge involution, so these can be interpreted as \"undirected\" property (multi)graphs.\n\nSee also: PropertyGraph.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.eprops-Tuple{AbstractPropertyGraph, Any}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.eprops","text":"Properties of edge in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.get_eprop-Tuple{AbstractPropertyGraph, Any, Symbol}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.get_eprop","text":"Get property of edge or edges in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.get_gprop-Tuple{AbstractPropertyGraph, Symbol}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.get_gprop","text":"Get graph-level property of a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.get_vprop-Tuple{AbstractPropertyGraph, Any, Symbol}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.get_vprop","text":"Get property of vertex or vertices in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.gprops-Tuple{AbstractPropertyGraph}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.gprops","text":"Graph-level properties of a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.set_eprop!-Tuple{AbstractPropertyGraph, Any, Symbol, Any}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.set_eprop!","text":"Set property of edge or edges in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.set_eprops!-Tuple{AbstractPropertyGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.set_eprops!","text":"Set multiple properties of an edge in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.set_gprop!-Tuple{AbstractPropertyGraph, Symbol, Any}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.set_gprop!","text":"Set graph-level property in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.set_gprops!-Tuple{AbstractPropertyGraph}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.set_gprops!","text":"Set multiple graph-level properties in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.set_vprop!-Tuple{AbstractPropertyGraph, Any, Symbol, Any}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.set_vprop!","text":"Set property of vertex or vertices in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.set_vprops!-Tuple{AbstractPropertyGraph, Int64}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.set_vprops!","text":"Set multiple properties of a vertex in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.PropertyGraphs.vprops-Tuple{AbstractPropertyGraph, Any}","page":"Graphs","title":"Catlab.Graphs.PropertyGraphs.vprops","text":"Properties of vertex in a property graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphAlgorithms","page":"Graphs","title":"Catlab.Graphs.GraphAlgorithms","text":"Algorithms on graphs based on C-sets.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphs/#Catlab.Graphs.GraphAlgorithms.connected_component_projection","page":"Graphs","title":"Catlab.Graphs.GraphAlgorithms.connected_component_projection","text":"Projection onto (weakly) connected components of a graph.\n\nReturns a function in FinSet{Int} from the vertex set to the set of components.\n\n\n\n\n\n","category":"function"},{"location":"apis/graphs/#Catlab.Graphs.GraphAlgorithms.connected_components-Tuple{ACSet}","page":"Graphs","title":"Catlab.Graphs.GraphAlgorithms.connected_components","text":"(Weakly) connected components of a graph.\n\nReturns a vector of vectors, which are the components of the graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphAlgorithms.enumerate_paths-Tuple{HasGraph}","page":"Graphs","title":"Catlab.Graphs.GraphAlgorithms.enumerate_paths","text":"Enumerate all paths of an acyclic graph, indexed by src+tgt\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphAlgorithms.topological_sort-Tuple{ACSet}","page":"Graphs","title":"Catlab.Graphs.GraphAlgorithms.topological_sort","text":"Topological sort of a directed acyclic graph.\n\nThe depth-first search algorithm is adapted from the function topological_sort_by_dfs in Graphs.jl.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphAlgorithms.transitive_reduction!-Tuple{ACSet}","page":"Graphs","title":"Catlab.Graphs.GraphAlgorithms.transitive_reduction!","text":"Transitive reduction of a DAG.\n\nThe algorithm computes the longest paths in the DAGs and keeps only the edges corresponding to longest paths of length 1. Requires a topological sort, which is computed if it is not supplied.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.complete_graph-Union{Tuple{T}, Tuple{Type{T}, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.complete_graph","text":"Complete graph on n vertices.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.cycle_graph-Union{Tuple{T}, Tuple{Type{T}, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.cycle_graph","text":"Cycle graph on n vertices.\n\nWhen n = 1, this is a loop graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.erdos_renyi-Union{Tuple{T}, Tuple{Type{T}, Int64, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.erdos_renyi","text":"erdos_renyi(GraphType, n, ne)\n\nCreate an Erdős–Rényi random graph with n vertices and ne edges.\n\nReferences\n\nhttps://github.com/JuliaGraphs/LightGraphs.jl/blob/2a644c2b15b444e7f32f73021ec276aa9fc8ba30/src/SimpleGraphs/generators/randgraphs.jl\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.erdos_renyi-Union{Tuple{T}, Tuple{Type{T}, Int64, Real}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.erdos_renyi","text":"erdos_renyi(GraphType, n, p)\n\nCreate an Erdős–Rényi random graph with n vertices. Edges are added between pairs of vertices with probability p.\n\nOptional Arguments\n\nseed=-1: set the RNG seed.\nrng: set the RNG directly\n\nReferences\n\nhttps://github.com/JuliaGraphs/LightGraphs.jl/blob/2a644c2b15b444e7f32f73021ec276aa9fc8ba30/src/SimpleGraphs/generators/randgraphs.jl\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.expected_degree_graph-Union{Tuple{T}, Tuple{Type{T}, Vector{<:Real}}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.expected_degree_graph","text":"expected_degree_graph(GraphType, ω)\n\nGiven a vector of expected degrees ω indexed by vertex, create a random undirected graph in which vertices i and j are connected with probability ω[i]*ω[j]/sum(ω).\n\nOptional Arguments\n\nseed=-1: set the RNG seed.\nrng: set the RNG directly\n\nImplementation Notes\n\nThe algorithm should work well for maximum(ω) << sum(ω). As maximum(ω) approaches sum(ω), some deviations from the expected values are likely.\n\nReferences\n\nConnected Components in Random Graphs with Given Expected Degree Sequences, Linyuan Lu and Fan Chung. https://link.springer.com/article/10.1007%2FPL00012580\nEfficient Generation of Networks with Given Expected Degrees, Joel C. Miller and Aric Hagberg. https://doi.org/10.1007/978-3-642-21286-4_10\nhttps://github.com/JuliaGraphs/LightGraphs.jl/blob/2a644c2b15b444e7f32f73021ec276aa9fc8ba30/src/SimpleGraphs/generators/randgraphs.jl#L187\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.parallel_arrows-Union{Tuple{T}, Tuple{Type{T}, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.parallel_arrows","text":"Graph with two vertices and n parallel edges.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.path_graph-Union{Tuple{T}, Tuple{Type{T}, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.path_graph","text":"Path graph on n vertices.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.star_graph-Union{Tuple{T}, Tuple{Type{T}, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.star_graph","text":"Star graph on n vertices.\n\nIn the directed case, the edges point outward.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.watts_strogatz-Union{Tuple{T}, Tuple{Type{T}, Integer, Integer, Real}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.watts_strogatz","text":"watts_strogatz(n, k, β)\n\nReturn a Watts-Strogatz small world random graph with n vertices, each with expected degree k (or `k\n\n1ifkis odd). Edges are randomized per the model based on probabilityβ`.\n\nThe algorithm proceeds as follows. First, a perfect 1-lattice is constructed, where each vertex has exacly div(k, 2) neighbors on each side (i.e., k or k - 1 in total). Then the following steps are repeated for a hop length i of 1 through div(k, 2).\n\nConsider each vertex s in turn, along with the edge to its ith nearest neighbor t, in a clockwise sense.\nGenerate a uniformly random number r. If r ≥ β, then the edge (s, t) is left unaltered. Otherwise, the edge is deleted and rewired so that s is connected to some vertex d, chosen uniformly at random from the entire graph, excluding s and its neighbors. (Note that t is a valid candidate.)\n\nFor β = 0, the graph will remain a 1-lattice, and for β = 1, all edges will be rewired randomly.\n\nOptional Arguments\n\nis_directed=false: if true, return a directed graph.\nseed=-1: set the RNG seed.\n\nReferences\n\nCollective dynamics of ‘small-world’ networks, Duncan J. Watts, Steven H. Strogatz. https://doi.org/10.1038/30918\nSmall Worlds, Duncan J. watts. https://en.wikipedia.org/wiki/Special:BookSources?isbn=978-0691005416\nhttps://github.com/JuliaGraphs/LightGraphs.jl/blob/2a644c2b15b444e7f32f73021ec276aa9fc8ba30/src/SimpleGraphs/generators/randgraphs.jl#L187\n\n\n\n\n\n","category":"method"},{"location":"apis/graphs/#Catlab.Graphs.GraphGenerators.wheel_graph-Union{Tuple{T}, Tuple{Type{T}, Int64}} where T<:ACSet","page":"Graphs","title":"Catlab.Graphs.GraphGenerators.wheel_graph","text":"Wheel graph on n vertices.\n\nIn the directed case, the outer cycle is directed and the spokes point outward.\n\n\n\n\n\n","category":"method"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"EditURL = \"../../../literate/sketches/partitions.jl\"","category":"page"},{"location":"generated/sketches/partitions/#Partitions","page":"Partitions","title":"Partitions","text":"","category":"section"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"(Image: )","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"Partitions are a categorical construction that we derive from sets and functions. Given a set A, you can think of all of the ways to partition A into parts. These ways of partitioning are isomorphic to equivalence relations R ⊆ A × A.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"The first step is our Catlab imports","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"using Core: GeneratedFunctionStub\nusing Test\n\nusing GATlab, Catlab.Theories, Catlab.CategoricalAlgebra\nimport Catlab.Theories: compose\nusing DataStructures\nusing PrettyTables\nPrettyTables.pretty_table(f::FinFunction, name::Symbol=:f) =\n pretty_table(OrderedDict(:x=>1:length(dom(f)), Symbol(\"$(name)(x)\")=>collect(f)))\nusing LaTeXStrings","category":"page"},{"location":"generated/sketches/partitions/#FinSet:-the-category-of-Finite-Sets","page":"Partitions","title":"FinSet: the category of Finite Sets","text":"","category":"section"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"In FinSet the objects are sets n = {1...n} and the morphisms are functions between finite sets. You can wrap a plain old Int into a finite set with the FinSet(n::Int) function. These sets will serve as the domain and codomains of our functions.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"n = FinSet(3)\nm = FinSet(4)","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"once you have some sets, you can define functions between them. A FinFunction from n to m, f:n→m, can be specified as an array of length n with elements from m.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"f = FinFunction([2,4,3], n, m)\n\npretty_table(f)","category":"page"},{"location":"generated/sketches/partitions/#Surjective-maps","page":"Partitions","title":"Surjective maps","text":"","category":"section"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"In order to use a map to represent a partition, we have to make sure that it is surjective. Given a FinFunction, we can compute the preimage of any element in its codomain.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"preimage(f, 2)\n\npreimage(f, 1)","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"If the preimage is empty, then there is no element in the domain that maps to that element of the codomain. This gives us a definition of surjective functions by asserting that all the preimages are nonempty. Julia note: !p is the predicate x ↦ ¬p(x), f.(A) applies f to all of the elements in A.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"is_surjective(f::FinFunction) = all((!isempty).(preimage(f,i) for i in codom(f)))\nis_surjective(f)","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"Our function f, wasn't surjective so it can't be used to induce a partition via its preimages. Let's try again,","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"g = FinFunction([1,2,3,3], m, n)\npretty_table(g, :g)\nis_surjective(g)","category":"page"},{"location":"generated/sketches/partitions/#Refinements-of-a-Partition","page":"Partitions","title":"Refinements of a Partition","text":"","category":"section"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"When defining partitions classically as A = ∪ₚ Aₚ with p ≠ r ⟹ Aₚ ≠ Aᵣ, it is not immediately obvious how to define comparisons between partitions. With the \"a partition of A is a surjective map out of A\" definition, the comparisons are obvious. The composition of surjective maps is surjective, so we can define the refinement order in terms of a diagram in Set.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"You can see a graphical definition in quiver","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"using TikzCDs\n\ntriangle = L\"\"\"\nA &&& Q \\\\\n\\\\\n&&& P\n\\arrow[\"h\", two heads, from=1-4, to=3-4]\n\\arrow[\"f\", two heads, from=1-1, to=1-4]\n\\arrow[\"g\"', two heads, from=1-1, to=3-4]\n\"\"\";\n\nTikzCD(triangle, preamble=TikzCDs.Styles.Quiver)","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"Let's take a look at an example:","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"A = FinSet(4)\nQ = FinSet(3)\nP = FinSet(2)\n\nf = FinFunction([1,2,3,3], A, Q)\ng = FinFunction([1,1,2,2], A, P)\nh = FinFunction([1,1,2], Q, P)\n\n@test_throws ErrorException compose(g,h) #Catlab checks the domains match\n\npretty_table(compose(f,h), Symbol(\"(f⋅h)\"))\n\ncompose(f,h) == g","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"This triangle commutes, so f is a refinement of g equivalently g is coarser than f.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"h′ = FinFunction([1,1], P, FinSet(1))\n\npretty_table(f⋅h⋅h′, Symbol(\"f⋅h⋅h′\"))","category":"page"},{"location":"generated/sketches/partitions/#Properties-of-refinements","page":"Partitions","title":"Properties of refinements","text":"","category":"section"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"We can show that refinement gives us a preorder on partitions directly from the nice properties of surjective maps.","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"Reflexive: Any partition is a refinement of itself.\nTransitive: If f ≤ g ≤ h as partitions, then f ≤ h","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"You can read these directly off the definition of refinements as a commutative triangle in the category of (Set, Surjections). You can edit this diagram in quiver","category":"page"},{"location":"generated/sketches/partitions/","page":"Partitions","title":"Partitions","text":"refinement = L\"\"\"\nA &&& Q \\\\\n\\\\\n&&& P \\\\\n\\\\\n&&& {Q^\\prime}\n\\arrow[\"h\", from=1-4, to=3-4]\n\\arrow[\"f\", two heads, from=1-1, to=1-4]\n\\arrow[\"g\"', two heads, from=1-1, to=3-4]\n\\arrow[\"{h^\\prime}\", from=3-4, to=5-4]\n\\arrow[\"{f\\cdot h\\cdot h^\\prime = g\\cdot h^\\prime}\"', two heads, from=1-1, to=5-4]\n\"\"\";\n\nTikzCD(refinement, preamble=TikzCDs.Styles.Quiver)","category":"page"},{"location":"apis/theories/#Standard-library-of-theories","page":"Standard library of theories","title":"Standard library of theories","text":"","category":"section"},{"location":"apis/theories/","page":"Standard library of theories","title":"Standard library of theories","text":"Through the module Catlab.Theories, Catlab provides a standard library of generalized algebraic theories for categories, monoidal categories, and other categorical structures. The theories correspond, in most cases, to standard definitions in category theory and they are used throughout Catlab and the AlgebraicJulia ecosystem to structure programs and provide a common interface for applied category theory. The module also provides default syntax systems for many of the theories.","category":"page"},{"location":"apis/theories/","page":"Standard library of theories","title":"Standard library of theories","text":"Categorical structures for which theories are provided include:","category":"page"},{"location":"apis/theories/","page":"Standard library of theories","title":"Standard library of theories","text":"categories\nmonoidal and symmetric monoidal categories\ncartesian and cocartesian categories\nsemiadditive categories/biproduct categories\nhypergraph categories\nbicategories of relations\ncategories with two monoidal products, such as distributive monoidal categories","category":"page"},{"location":"apis/theories/","page":"Standard library of theories","title":"Standard library of theories","text":"The contents of this module can be supplemented by the user, and it is even possible to use many parts of Catlab without using this module. The user is free to create new syntax systems for the theories defined here and also to define entirely new theories.","category":"page"},{"location":"apis/theories/","page":"Standard library of theories","title":"Standard library of theories","text":"Modules = [ Theories ]\nPrivate = false","category":"page"},{"location":"apis/theories/#Catlab.Theories","page":"Standard library of theories","title":"Catlab.Theories","text":"Catlab's standard library of generalized algebraic theories.\n\nThe focus is on categories and monoidal categories, but other related structures are also included.\n\n\n\n\n\n","category":"module"},{"location":"apis/theories/#Catlab.Theories.CategoryExpr","page":"Standard library of theories","title":"Catlab.Theories.CategoryExpr","text":"Base type for GAT expressions in categories or other categorical structures.\n\nAll symbolic expression types exported by Catlab.Theories are subtypes of this abstract type.\n\n\n\n\n\n","category":"type"},{"location":"apis/theories/#Catlab.Theories.HomExpr","page":"Standard library of theories","title":"Catlab.Theories.HomExpr","text":"Base type for morphism expressions in categorical structures.\n\n\n\n\n\n","category":"type"},{"location":"apis/theories/#Catlab.Theories.ObExpr","page":"Standard library of theories","title":"Catlab.Theories.ObExpr","text":"Base type for object expressions in categorical structures.\n\n\n\n\n\n","category":"type"},{"location":"apis/theories/#Base.collect-Tuple{ObExpr}","page":"Standard library of theories","title":"Base.collect","text":"Collect generators of object in monoidal category as a vector.\n\n\n\n\n\n","category":"method"},{"location":"apis/theories/#Base.ndims-Tuple{ObExpr}","page":"Standard library of theories","title":"Base.ndims","text":"Number of \"dimensions\" of object in monoidal category.\n\n\n\n\n\n","category":"method"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"EditURL = \"../../../literate/graphics/graphviz_wiring_diagrams.jl\"","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Drawing-wiring-diagrams-in-Graphviz","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"(Image: )","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"Catlab can draw wiring diagrams using Graphviz. Directed wiring diagrams are drawn using the dot program and undirected wiring diagrams using neato and fdp. This feature requires that Graphviz be installed, but does not require any additional Julia packages.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"using Catlab.WiringDiagrams, Catlab.Graphics","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Directed-wiring-diagrams","page":"Drawing wiring diagrams in Graphviz","title":"Directed wiring diagrams","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Symmetric-monoidal-category","page":"Drawing wiring diagrams in Graphviz","title":"Symmetric monoidal category","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"using Catlab.Theories\n\nA, B = Ob(FreeSymmetricMonoidalCategory, :A, :B)\nf = Hom(:f, A, B)\ng = Hom(:g, B, A)\nh = Hom(:h, otimes(A,B), otimes(A,B));\nnothing #hide","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"To start, here are a few very simple examples.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(f)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(compose(f,g))","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(otimes(f,g))","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"In the next example, notice how Graphviz automatically \"untwists\" the double braiding to minimize edge crossings.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(compose(braid(A,A), otimes(f,f), braid(B,B)))","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"Here is a larger composite morphism.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"composite = compose(otimes(g,f), h, otimes(f,g))\nto_graphviz(composite)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"By default, the wiring diagram is laid out from top to bottom. Other layout orientations can be requested, such as left-to-right or bottom-to-top:","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(composite, orientation=LeftToRight)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(composite, orientation=BottomToTop)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"When working with very large diagrams (larger than the ones shown here), it is sometimes convenient to omit the ports of the outer box and any wires attached to them.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(composite, outer_ports=false)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Biproduct-category","page":"Drawing wiring diagrams in Graphviz","title":"Biproduct category","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"A, B = Ob(FreeBiproductCategory, :A, :B)\nf = Hom(:f, A, B)\ng = Hom(:g, B, A);\nnothing #hide","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"By default, copies and merges are drawn the way they are represented internally, as multiple wires.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"f1 = compose(mcopy(A), otimes(f,f))\nto_graphviz(f1)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"f2 = compose(mcopy(A), otimes(f,f), mmerge(B))\nto_graphviz(f2)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"To draw nodes for copies and merges, we need to add junctions to the wiring diagram.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(add_junctions!(to_wiring_diagram(f1)))","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(add_junctions!(to_wiring_diagram(f2)))","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Traced-monoidal-category","page":"Drawing wiring diagrams in Graphviz","title":"Traced monoidal category","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"A, B, X, Y = Ob(FreeTracedMonoidalCategory, :A, :B, :X, :Y)\nf = Hom(:f, otimes(X,A), otimes(X,B))\n\nto_graphviz(trace(X, A, B, f))","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(trace(X, A, B, f), orientation=LeftToRight)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"g, h = Hom(:g, A, A), Hom(:h, B, B)\n\ntrace_naturality = trace(X, A, B, compose(otimes(id(X),g), f, otimes(id(X),h)))\nto_graphviz(trace_naturality, orientation=LeftToRight)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Undirected-wiring-diagrams","page":"Drawing wiring diagrams in Graphviz","title":"Undirected wiring diagrams","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"The composite of two binary relations:","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"using Catlab.Programs: @relation\n\ndiagram = @relation (x,z) where (x,y,z) begin\n R(x,y)\n S(y,z)\nend\nto_graphviz(diagram, box_labels=:name)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"A \"wheel\"-shaped composition of relations:","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"diagram = @relation (x,y,z) where (w,x,y,z) begin\n R(x,w)\n S(y,w)\n T(z,w)\nend\nto_graphviz(diagram, box_labels=:name)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"As these examples show, the box_labels keyword argument specifies the data attribute of boxes to use for box labels, if any. The boolean argument port_labels controls the labeling of ports by numerical values and the argument junction_labels specifies the data attribute of junctions to use for junction labels. Note that the macro @relation creates wiring diagrams with name attribute for boxes and variable attribute for junctions.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(diagram, box_labels=:name,\n port_labels=false, junction_labels=:variable)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"By default, all junctions are shown. The keyword argument implicit_junctions omits any junctions which have exactly two incident ports.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"to_graphviz(diagram, box_labels=:name,\n port_labels=false, implicit_junctions=true)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Custom-styles","page":"Drawing wiring diagrams in Graphviz","title":"Custom styles","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"The visual appearance of wiring diagrams can be customized by setting Graphviz attributes at the graph, node, edge, and cell levels. Graph, node, and edge attributes are described in the Graphviz documentation. Cell attributes are passed to the primary cell of the HTML-like label used for the boxes.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"A, B, C = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C)\nf, g = Hom(:f, A, B), Hom(:g, B, C)\n\nto_graphviz(compose(f,g),\n labels = true, label_attr=:headlabel,\n node_attrs = Dict(\n :fontname => \"Courier\",\n ),\n edge_attrs = Dict(\n :fontname => \"Courier\",\n :labelangle => \"25\",\n :labeldistance => \"2\",\n ),\n cell_attrs = Dict(\n :bgcolor => \"lavender\",\n )\n)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/#Output-formats","page":"Drawing wiring diagrams in Graphviz","title":"Output formats","text":"","category":"section"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"The function to_graphviz returns an object of a type Graphviz.Graph, representing a Graphviz graph as an abstract syntax tree. When displayed interactively, this object is automatically run through Graphviz and rendered as an SVG image. Sometimes it is convenient to perform this process manually, to change the output format or further customize the generated dot file.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"To generate a dot file, use the builtin pretty-printer. This feature does not require Graphviz to be installed.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"using Catlab.Graphics: Graphviz\n\ngraph = to_graphviz(compose(f,g))\nGraphviz.pprint(graph)","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"Catlab provides a simple wrapper around the Graphviz command-line programs. For example, here is the JSON output for the graph.","category":"page"},{"location":"generated/graphics/graphviz_wiring_diagrams/","page":"Drawing wiring diagrams in Graphviz","title":"Drawing wiring diagrams in Graphviz","text":"import JSON3\n\nJSON3.read(Graphviz.run_graphviz(graph, format=\"json0\"))","category":"page"},{"location":"devdocs/style/#Style-Guide-for-AlgebraicJulia","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"The purpose of this document is to have a consistent style across AlgebraicJulia, for interests of maintainability and professionalism.","category":"page"},{"location":"devdocs/style/#Folder-structure","page":"Style Guide for AlgebraicJulia","title":"Folder structure","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"We follow the Julia project folder structure, where the most important elements are","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"A Project.toml file, describing dependencies and metadata.\nA src directory. Most functionality should be implemented in this directory.\nA test directory. Functionality implemented in src should be tested here.\nA README.md. This should describe the purpose of the project.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Additional directories one might also use","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"A notebooks directory for explanatory notebooks.\nA docs directory with Documenter.jl-generated docs.\nA scripts directory with executable scripts. Note: these scripts should not contain many functions or types, they should be thin wrappers around functions from src. It is acceptable to develop some functionality in a script if that functionality is eventually migrated into src.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"For most repositories in AlgebraicJulia, this should describe the top-level structure. However, some repositories might be multi-project. In that case, there is a top-level directory consisting of project directories, some of which may depend on each other.","category":"page"},{"location":"devdocs/style/#Naming-conventions","page":"Style Guide for AlgebraicJulia","title":"Naming conventions","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"There are two ways of joining words together without spaces that are in use across AlgebraicJulia.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"UpperCamelCase, in which each word is capitalized, and then joined together without a separating character.\nlower_snake_case, in which each word is lowercase, and then joined together with underscores. The use of uppercase acronyms in lower_snake_case is tolerable but discouraged.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Occasionally, it is also acceptable to join lowercase words together without underscores, e.g., setindex! instead of set_index!; judgement about readability and consistency should be used when making the decision to use underscores or not.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Here are some example of names that are not consistent with the AlgebraicJulia style.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"camelCase\nUpperCamel_and_snake\nDashed-name","category":"page"},{"location":"devdocs/style/#Projects","page":"Style Guide for AlgebraicJulia","title":"Projects","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Projects should be named using UpperCamelCase with a .jl suffix, e.g. AlgebraicPetri.jl or Semagrams.jl.","category":"page"},{"location":"devdocs/style/#Files-and-directories","page":"Style Guide for AlgebraicJulia","title":"Files and directories","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Directories should all be lower_snake_case, except for top-level directories that are named after projects.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Library julia files and test julia files should be named with UpperCamelCase. Scripts and notebooks should be lower_snake_case.","category":"page"},{"location":"devdocs/style/#Julia-values","page":"Style Guide for AlgebraicJulia","title":"Julia values","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Modules and types should always be UpperCamelCase. Functions should always be lower_snake_case, and ideally single words. Constants should be lower_snake_case, or occasionally SCREAMING_SNAKE_CASE (judgement should be exercised about use of SCREAMING_SNAKE_CASE). Fields of structs should be lower_snake_case, or ideally lowercase single words.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Arguments to functions should have short names, often just single letters. If your function is so specific that the arguments need to be described with long argument names, consider generalizing your function. If arguments need to be longer, then lower_snake_case should be used. Additionally, you can use types and comments to document what a variable is for instead of making the names long. Some examples:","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"f(a_natural_number) # BAD\nf(n::Nat) # GOOD\nf(graph, vector_of_weights) # BAD\nf(g::AbstractGraph, v::AbstractVector) # GOOD","category":"page"},{"location":"devdocs/style/#General-style-tips","page":"Style Guide for AlgebraicJulia","title":"General style tips","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"See the official Julia style guide for general guidelines but note the following additions and exceptions:","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Indent width is 2 spaces. For VSCode, go to settings and set Editor: Tab Size to 2.\nTry to avoid lines longer than 80 characters. Occasionally it may be convenient to go over slightly, but never do so egregiously. To hard wrap docstrings in VSCode, the extension Rewrap adds the keybinding Alt+Q (as in Emacs).\nIntroduce a new struct when many (≥3) functions have overlapping arguments that are common aspects of a shared concept\nCatlab uses modules more often than most Julia packages. While this may be idiosyncratic, it helps keep different components of Catlab isolated, which will be useful in the future when we spin out modules as their own packages.\nPrefer accessor and mutator functions (e.g. dom(f)) over direct manipulation of struct fields or keys (e.g. f.dom), especially when the functions already exist. This convention supports writing generic code and makes it easier to change data structure internals without breaking existing code.\nIn long files, using comment headers can improve readability and navigability. Top-level headers and sub-headers should be formatted as:","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"# Section\n#########\n\n# Subsection\n#-----------","category":"page"},{"location":"devdocs/style/#Guidelines-for-pull-requests","page":"Style Guide for AlgebraicJulia","title":"Guidelines for pull requests","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Every pull request to Catlab should be reviewed by at least one person. Following are some things to check when making a PR yourself or reviewing someone else's PR. The goal of this list is to ensure that the Catlab codebase is robust and maintainable. When any of these guidelines are violated, it should be documented in a comment on the PR page.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Note: This list only includes the mechanical things. When a reviewing a PR you should always use your own judgment in asking questions and making comments about API and algorithm design. That's the hard part!","category":"page"},{"location":"devdocs/style/#Tests-and-code-coverage","page":"Style Guide for AlgebraicJulia","title":"Tests and code coverage","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Enhancements (new features) must have accompanying unit tests\nBug fixes should come with unit tests exposing the bug, unless producing a minimal example is unusually difficult\nDo not delete existing unit tests, unless you have a very good reason (e.g., the relevant functionality is being moved to another package), which is documented in the PR\nIf you are adding a new module, make sure to add the test module to the test runner (test/runtests.jl or file included therein)\nCode coverage on the Catlab repo exceeds 90% and we try to keep it that way. We do not insist on 100% coverage, which is impractical, nor do we set a hard threshold applicable to all PRs, but generally you should aim for 90%+ code coverage. Any reductions in test coverage should be justified in the PR.","category":"page"},{"location":"devdocs/style/#Documentation","page":"Style Guide for AlgebraicJulia","title":"Documentation","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"All exported functions, types, and constants must have docstrings\nDocstrings should be written in complete sentences, with correct capitalization and punctuation. Likewise for comments, except for fragmentary end-of-line comments.\nWhere possible, provide citations for constructions and algorithms that you implement. This reflects good scholarly values and also aids the understanding of your code by other people.","category":"page"},{"location":"devdocs/style/#Version-control","page":"Style Guide for AlgebraicJulia","title":"Version control","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Commit messages should be informative and be written in complete sentences\nAvoid one-word commit messages like \"fix\" or \"bug\". If you need to make very simple fixes on your branch, amend a previous commit and force push.\nAvoid repeatedly merging the main branch back into your PR branch. Instead, rebase off main and force push.","category":"page"},{"location":"devdocs/style/#Backwards-compatibility","page":"Style Guide for AlgebraicJulia","title":"Backwards compatibility","text":"","category":"section"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Reflecting Catlab's dual status as a research project and a user-facing library, we want to give ourselves space to experiment while also not annoying our users and each other by needlessly breaking things.","category":"page"},{"location":"devdocs/style/","page":"Style Guide for AlgebraicJulia","title":"Style Guide for AlgebraicJulia","text":"Like other Julia packages, Catlab aims to follow semantic versioning\nAll else equal, it is better to make breaking changes to new APIs, especially very new ones, than old APIs\nIf you plan to make major breaking changes, please coordinate with the senior developers to ensure that it makes senses and aligns with the release schedule","category":"page"},{"location":"apis/graphics/#graphics","page":"Graphics","title":"Graphics","text":"","category":"section"},{"location":"apis/graphics/","page":"Graphics","title":"Graphics","text":"Modules = [\n Graphics.GraphvizGraphs,\n Graphics.ComposeWiringDiagrams,\n Graphics.GraphvizWiringDiagrams,\n Graphics.TikZWiringDiagrams,\n Graphics.WiringDiagramLayouts,\n]\nPrivate = false","category":"page"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs","text":"Graphviz support for Catlab's graph types.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.parse_graphviz-Tuple{AbstractDict}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.parse_graphviz","text":"Parse Graphviz output in JSON format.\n\nReturns a property graph with graph layout and other metadata. Each node has a position and size.\n\nAll units are in points. Note that Graphviz has 72 points per inch.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Tuple{AbstractPropertyGraph}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Convert a property graph to a Graphviz graph.\n\nThis method is usually more convenient than direct AST manipulation for creating simple Graphviz graphs. For more advanced features, like nested subgraphs, you must use the Graphviz AST.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Tuple{AbstractUndirectedBipartiteGraph}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Visualize a bipartite graph using Graphviz.\n\nWorks for both directed and undirected bipartite graphs. Both types of vertices in the bipartite graph become nodes in the Graphviz graph.\n\nArguments\n\nprog=\"dot\": Graphviz program to use\ngraph_attrs: Graph-level Graphviz attributes\nnode_attrs: Node-level Graphviz attributes\nedge_attrs: Edge-level Graphviz attributes\nnode_labels=false: whether to label nodes and if so, which pair of data attributes to use\nedge_labels=false: whether to label edges and if so, which data attribute (undirected case) or pair of attributes (directed case) to use\ninvis_edge=true: whether to add invisible edges between vertices of same type, which ensures that the order of the nodes is preserved.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Tuple{HasGraph}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Convert a graph to a Graphviz graph.\n\nA simple default style is applied. For more control over the visual appearance, first convert the graph to a property graph, define the Graphviz attributes as needed, and finally convert the property graph to a Graphviz graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Union{Tuple{StructACSetTransformation{S, Comp, <:AbstractGraph, <:AbstractGraph}}, Tuple{Comp}, Tuple{S}} where {S, Comp}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Visualize a graph homomorphism using Graphviz.\n\nVisualize a homomorphism (ACSetTransformation) between two graphs (instances of AbstractGraph). By default, the domain and codomain are drawn as subgraphs and the vertex mapping is drawn using dotted edges, whereas the edge map is suppressed. The vertex and edge mapping can also be shown using colors, via the node_colors and edge_colors keyword arguments.\n\nArguments\n\ndraw_codom=true: whether to draw the codomain graph\ndraw_mapping=true: whether to draw the vertex mapping using edges\nprog=\"dot\": Graphviz program to use\ngraph_attrs: Graph-level Graphviz attributes\nnode_attrs: Node-level Graphviz attributes\nedge_attrs: Edge-level Graphviz attributes\nnode_labels=false: whether to draw node labels and which vertex attribute to use\nedge_labels=false: whether to draw edge labels and which edge attribute to use\nnode_colors=!draw_codom: whether and how to color nodes based on vertex map\nedge_colors=!draw_codom: whether and how to color edges based on edge map\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz_property_graph-Tuple{AbstractGraph}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz_property_graph","text":"Convert graph or other structure to a property graph suitable for Graphviz.\n\nThis function is an intermediate step in many methods of the generic function to_graphviz, but can be useful in its own right for customizing the Graphviz graph beyond whatever options are supported by to_graphviz.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.ComposeWiringDiagrams","page":"Graphics","title":"Catlab.Graphics.ComposeWiringDiagrams","text":"Draw wiring diagrams using Compose.jl.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphics/#Catlab.Graphics.ComposeWiringDiagrams.ComposePicture","page":"Graphics","title":"Catlab.Graphics.ComposeWiringDiagrams.ComposePicture","text":"A Compose context together with a given width and height.\n\nWe need this type because contexts have no notion of size or aspect ratio, but wiring diagram layouts have fixed aspect ratios.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphics/#Catlab.Graphics.ComposeWiringDiagrams.layout_to_composejl-Tuple{WiringDiagram}","page":"Graphics","title":"Catlab.Graphics.ComposeWiringDiagrams.layout_to_composejl","text":"Draw a wiring diagram in Compose.jl using the given layout.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.ComposeWiringDiagrams.to_composejl-Tuple","page":"Graphics","title":"Catlab.Graphics.ComposeWiringDiagrams.to_composejl","text":"Draw a wiring diagram in Compose.jl.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizWiringDiagrams","page":"Graphics","title":"Catlab.Graphics.GraphvizWiringDiagrams","text":"Lay out and draw wiring diagrams using Graphviz.\n\nThis module requires Graphviz v2.42 or higher.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Tuple{AbstractUWD}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Draw an undirected wiring diagram using Graphviz.\n\nCreates an undirected, bipartite Graphviz graph, with the boxes and outer ports of the diagram becoming nodes of one kind and the junctions of the diagram becoming nodes of the second kind.\n\nArguments\n\ngraph_name=\"G\": name of Graphviz graph\nprog=\"neato\": Graphviz program, usually \"neato\" or \"fdp\"\nbox_labels=false: if boolean, whether to label boxes with their number; if a symbol, name of data attribute for box label\nport_labels=false: whether to label ports with their number\njunction_labels=false: if boolean, whether to label junctions with their number; if a symbol, name of data attribute for junction label\njunction_size=\"0.075\": size of junction nodes, in inches\nimplicit_junctions=false: whether to represent a junction implicity as a wire when it has exactly two incident ports\ngraph_attrs=Dict(): top-level graph attributes\nnode_attrs=Dict(): top-level node attributes\nedge_attrs=Dict(): top-level edge attributes\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Tuple{CPortGraph}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Draw a circular port graph using Graphviz.\n\nCreates a Graphviz graph. Ports are currently not respected in the image, but the port index for each box can be displayed to provide clarification.\n\nArguments\n\ngraph_name=\"G\": name of Graphviz graph\nprog=\"neato\": Graphviz program, usually \"neato\" or \"fdp\"\nbox_labels=false: whether to label boxes with their number\nport_labels=false: whether to label ports with their number\ngraph_attrs=Dict(): top-level graph attributes\nnode_attrs=Dict(): top-level node attributes\nedge_attrs=Dict(): top-level edge attributes\n\nTODO: The lack of ports might be able to be resolved by introducing an extra node per port which is connected to its box with an edge of length 0.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizGraphs.to_graphviz-Tuple{WiringDiagram}","page":"Graphics","title":"Catlab.Graphics.GraphvizGraphs.to_graphviz","text":"Draw a wiring diagram using Graphviz.\n\nThe input can also be a morphism expression, in which case it is first converted into a wiring diagram. This function requires Graphviz v2.42 or higher.\n\nArguments\n\ngraph_name=\"G\": name of Graphviz digraph\norientation=TopToBottom: orientation of layout. One of LeftToRight, RightToLeft, TopToBottom, or BottomToTop.\nnode_labels=true: whether to label the nodes\nlabels=false: whether to label the edges\nlabel_attr=:label: what kind of edge label to use (if labels is true). One of :label, :xlabel, :headlabel, or :taillabel.\nport_size=\"24\": minimum size of ports on box, in points\njunction_size=\"0.05\": size of junction nodes, in inches\nouter_ports=true: whether to display the outer box's input and output ports. If disabled, no incoming or outgoing wires will be shown either!\nanchor_outer_ports=true: whether to enforce ordering of the outer box's input and output, i.e., ordering of the incoming and outgoing wires\ngraph_attrs=Dict(): top-level graph attributes\nnode_attrs=Dict(): top-level node attributes\nedge_attrs=Dict(): top-level edge attributes\ncell_attrs=Dict(): main cell attributes in node HTML-like label\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.GraphvizWiringDiagrams.graphviz_layout-Tuple{WiringDiagram}","page":"Graphics","title":"Catlab.Graphics.GraphvizWiringDiagrams.graphviz_layout","text":"Lay out directed wiring diagram using Graphviz.\n\nNote: At this time, only the positions and sizes of the boxes, and the positions of the outer ports, are used. The positions of the box ports and the splines for the wires are ignored.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.TikZWiringDiagrams","page":"Graphics","title":"Catlab.Graphics.TikZWiringDiagrams","text":"Draw wiring diagrams using TikZ.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphics/#Catlab.Graphics.TikZWiringDiagrams.layout_to_tikz-Tuple{WiringDiagram}","page":"Graphics","title":"Catlab.Graphics.TikZWiringDiagrams.layout_to_tikz","text":"Draw a wiring diagram in TikZ using the given layout.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.TikZWiringDiagrams.to_tikz-Tuple","page":"Graphics","title":"Catlab.Graphics.TikZWiringDiagrams.to_tikz","text":"Draw a wiring diagram in TikZ.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.WiringDiagramLayouts","page":"Graphics","title":"Catlab.Graphics.WiringDiagramLayouts","text":"Backend-agnostic layout of wiring diagrams via morphism expressions.\n\nThis module lays out wiring diagrams for visualization, independent of any specific graphics system. It uses the structure of a morphism expression to determine the layout. Thus, the first step of the algorithm is to convert the wiring diagram to a symbolic expression, using the submodule WiringDiagrams.Expressions. Morphism expressions may also be given directly.\n\n\n\n\n\n","category":"module"},{"location":"apis/graphics/#Catlab.Graphics.WiringDiagramLayouts.LayoutOrientation","page":"Graphics","title":"Catlab.Graphics.WiringDiagramLayouts.LayoutOrientation","text":"Orientation of wiring diagram.\n\n\n\n\n\n","category":"type"},{"location":"apis/graphics/#Catlab.Graphics.WiringDiagramLayouts.layout_box-Tuple{Vector, Vector, Catlab.Graphics.WiringDiagramLayouts.LayoutOptions}","page":"Graphics","title":"Catlab.Graphics.WiringDiagramLayouts.layout_box","text":"Lay out a box and its ports.\n\nBy default the box is rectangular, but other shapes are also supported.\n\n\n\n\n\n","category":"method"},{"location":"apis/graphics/#Catlab.Graphics.WiringDiagramLayouts.layout_diagram-Tuple{Module, WiringDiagram}","page":"Graphics","title":"Catlab.Graphics.WiringDiagramLayouts.layout_diagram","text":"Lay out a wiring diagram or morphism expression for visualization.\n\nIf a wiring diagram is given, it is first to converted to a morphism expression.\n\nThe layout is calculated with respect to a cartesian coordinate system with origin at the center of the diagram and the positive y-axis pointing downwards. Box positions are relative to their centers. All positions and sizes are dimensionless (unitless).\n\n\n\n\n\n","category":"method"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"EditURL = \"../../../literate/graphs/subgraphs.jl\"","category":"page"},{"location":"generated/graphs/subgraphs/#Algebra-of-subgraphs","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"","category":"section"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(Image: )","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"using Catlab.Graphs, Catlab.Graphics\nusing Catlab.Theories, Catlab.CategoricalAlgebra","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"A subgraph of a graph G is a monomorphism A rightarrowtail G. Because the category of graphs is a presheaf topos, its subobjects have a rich algebraic structure, which we will explore in this vignette.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Throughout the vignette, we will work with subgraphs of the following graph.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"G = cycle_graph(Graph, 4) ⊕ path_graph(Graph, 2) ⊕ cycle_graph(Graph, 1)\nadd_edge!(G, 3, add_vertex!(G))\n\nto_graphviz(G, node_labels=true, edge_labels=true)","category":"page"},{"location":"generated/graphs/subgraphs/#Meet-and-join","page":"Algebra of subgraphs","title":"Meet and join","text":"","category":"section"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"The basic operations of meet or intersection (wedge), join or union (vee), top or maximum (top), bottom or minimum (bot) are all computed pointwise: separately on vertices and edges.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Consider the following two subgraphs.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(A = Subobject(G, V=1:4, E=[1,2,4])) |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(B = Subobject(G, V=[2,3,4,7,8], E=[2,3,6,7])) |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"The join is defined as left adjoint to the diagonal, making it the least upper bound:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"A vee B leq C qquadtextiffqquad A leq C text and B leq C","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"A ∨ B |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Dually, the meet is defined as right adjoint to the diagonal, making it the greatest lower bound:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"C leq A text and C leq B qquadtextiffqquad C leq A wedge B","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"A ∧ B |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/#Implication-and-negation","page":"Algebra of subgraphs","title":"Implication and negation","text":"","category":"section"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"The other operations, beginning with implication (Rightarrow) and negation (neg) are more interesting because they do not have pointwise formulas.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Implication is defined as the right adjoint to the meet:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"C wedge A leq B qquadtextiffqquad C leq A Rightarrow B","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(A ⟹ B) |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Negation is defined by setting B = bot in the above formula:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"C wedge A = bot qquadtextiffqquad C leq neg A","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"¬A |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/#Induced-subgraph-as-a-double-negation","page":"Algebra of subgraphs","title":"Induced subgraph as a double negation","text":"","category":"section"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"The logic of subgraphs, and of subobjects in presheaf toposes generally, is not classical. Specifically, subobjects form a Heyting algebra but not a Boolean algebra. This means that the law of excluded middle does not hold: in general, neg neg A neq A.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Applying the double negation to a discrete subgraph gives the subgraph induced by those vertices.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(C = Subobject(G, V=1:4)) |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"¬(¬C) |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/#Subtraction-and-non","page":"Algebra of subgraphs","title":"Subtraction and non","text":"","category":"section"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"The subojects also form co-Heyting algebra and hence a bi-Heyting algebra.","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Subtraction is defined dually to implication as the left adjoint to the join:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"A leq B vee C qquadtextiffqquad A setminus B leq C","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(A \\ B) |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"Non is defined by setting A = top in the above formula:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"top = B vee C qquadtextiffqquad sim B leq C","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"~A |> to_graphviz","category":"page"},{"location":"generated/graphs/subgraphs/#Boundary-via-non","page":"Algebra of subgraphs","title":"Boundary via non","text":"","category":"section"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"A boundary operator can be defined using the non operator:","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"partial A = A wedge sim A","category":"page"},{"location":"generated/graphs/subgraphs/","page":"Algebra of subgraphs","title":"Algebra of subgraphs","text":"(A ∧ ~A) |> to_graphviz","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"EditURL = \"../../../literate/wiring_diagrams/diagrams_and_expressions.jl\"","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/#Wiring-diagrams-and-syntactic-expressions","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"","category":"section"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"(Image: )","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"Morphisms in a monoidal category can be represented as syntactic expressions, such as f cdot g and f otimes g, and also as wiring diagrams, aka string diagrams. Catlab provides facilities for transforming between these two representations.","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"using Catlab.Theories, Catlab.WiringDiagrams\nusing Catlab.Graphics\n\nfunction show_diagram(d::WiringDiagram)\n to_graphviz(d, orientation=LeftToRight, labels=false)\nend","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/#Expressions-to-diagrams","page":"Wiring diagrams and syntactic expressions","title":"Expressions to diagrams","text":"","category":"section"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"Converting a morphism expression to a wiring diagram is conceptually and algorithmically simple, because every expression determines a unique diagram.","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"As a simple example, here is the monoidal product of two generators, f and g, first as an expression (displayed using LaTeX) and then as a wiring diagram (displayed using Graphviz).","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"A, B, C, D, E = Ob(FreeCartesianCategory, :A, :B, :C, :D, :E)\nf = Hom(:f, A, B)\ng = Hom(:g, B, C)\n\nexpr = f ⊗ g","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"show_diagram(to_wiring_diagram(expr))","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"Here is a monoidal product of compositions:","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"h = Hom(:h, C, D)\nk = Hom(:k, D, E)\n\nexpr = (f ⋅ g) ⊗ (h ⋅ k)","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"show_diagram(to_wiring_diagram(expr))","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/#Diagrams-to-expressions","page":"Wiring diagrams and syntactic expressions","title":"Diagrams to expressions","text":"","category":"section"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"Converting a wiring diagram to a syntactic expression is algorithmically more challenging, due to the fact that a single wiring diagram generally admits many different representations as an expression. Thus, a particular expression must be singled out.","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"To bring this out, we define a function that round-trips a morphism expression to a wiring diagram and then back to an expression.","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"function roundtrip_expr(expr::FreeCartesianCategory.Hom)\n d = to_wiring_diagram(expr)\n to_hom_expr(FreeCartesianCategory, d)\nend","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"We can recover the expression just considered above:","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"roundtrip_expr((f ⋅ g) ⊗ (h ⋅ k))","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"But here is a different expression that round-trips to the same thing:","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"roundtrip_expr((f ⊗ h) ⋅ (g ⊗ k))","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"The equality of these two expressions,","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"(f cdot g) otimes (h cdot k) = (f otimes h) cdot (g otimes k)","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"is the interchange law in a monoidal category. It says that composition and monoidal products can be interchanged. As this example shows, the conversion algorithm in Catlab favors products over composition, placing products towards the root of the expression tree wherever possible. Other laws can be discovered by this procedure. Since we are working in a cartesian monoidal category, operations of copying, Delta_A A to A otimes A, and deleting, lozenge_A A to I, are available.","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"Consider the operation of copying the product A otimes B.","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"expr = mcopy(A ⊗ B)","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"show_diagram(add_junctions!(to_wiring_diagram(expr)))","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"roundtrip_expr(expr)","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"The equation just witnessed,","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"Delta_A otimes B = (Delta_A otimes Delta_B) cdot (1_A otimes sigma_AB otimes 1_B)","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"is one of the coherence laws for cartesian products (arXiv:0908.3347, Table 7). Another coherence law for products is","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"lozenge_A otimes B = lozenge_A otimes lozenge_B","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"expr = delete(A ⊗ B)","category":"page"},{"location":"generated/wiring_diagrams/diagrams_and_expressions/","page":"Wiring diagrams and syntactic expressions","title":"Wiring diagrams and syntactic expressions","text":"roundtrip_expr(expr)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"EditURL = \"../../../literate/sketches/cat_elements.jl\"","category":"page"},{"location":"generated/sketches/cat_elements/#The-Category-of-Elements","page":"The Category of Elements","title":"The Category of Elements","text":"","category":"section"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"A very useful construction in applied category theory is the Category of Elements, which is also called the Grothendieck construction. This is a very general technique in category theory, but we will look at how you can use it to explain why graphs are so useful in computer science. We have already seen that C-Sets are a model of relational databases that can be used to store data as a collection of interlocking tables. Relational databases are the bread and butter of the computing industry. Every company on earth uses software that is backed by a relational database. Most data that is not stored in a relational DB is often stored in some kind of graph data structure. This sketch will show how these approaches are interchangeable via the category of elements, which associates to every database instance a graph and a graph homomorphism into the schema of the graph.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"using GATlab, Catlab.CategoricalAlgebra, Catlab.Graphs, Catlab.Graphics\nusing Colors","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"Let's tell Catlab how to draw categories of elements.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"function graph(el::Elements)\n F = FinFunctor(Dict(:V => :El, :E => :Arr), Dict(:src => :src, :tgt => :tgt),\n SchGraph, SchElements)\n ΔF = DataMigrationFunctor(F, Elements{Symbol}, Graph)\n return ΔF(el)\nend\n\nsafecolors(start, stop, len) = if len > 1\n return hex.(range(start, stop=stop, length=len))\nelse\n return [hex.(start)]\nend\n\nfunction draw(f::Elements; kw...)\n pg = to_graphviz_property_graph(graph(f);\n node_labels=true, edge_labels=true, prog=\"neato\", kw...)\n vcolors = safecolors(colorant\"#0021A5\", colorant\"#FA4616\", nparts(f, :Ob))\n ecolors = safecolors(colorant\"#6C9AC3\", colorant\"#E28F41\", nparts(f, :Hom))\n for v in parts(f, :El)\n fv = f[v, :πₑ]\n set_vprops!(pg, v, Dict(:color => \"#$(vcolors[fv])\", :label=>\"$v:$(f[v,[:πₑ, :nameo]])\"))\n end\n for e in parts(f, :Arr)\n fe = f[e, :πₐ]\n set_eprops!(pg, e, Dict(:color => \"#$(ecolors[fe])\"))\n end\n to_graphviz(pg)\nend\n\ndraw(g) = to_graphviz(g, node_labels=true, edge_labels=true, prog=\"neato\")","category":"page"},{"location":"generated/sketches/cat_elements/#The-simplest-schema","page":"The Category of Elements","title":"The simplest schema","text":"","category":"section"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"First we will look at discrete dynamical systems. The set S is our state space and the funct nxt associates to every state, the next state in the system. This is a deterministic dynamical system with finitely many states and discrete time.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"@present SchDDS(FreeSchema) begin\n S::Ob\n nxt::Hom(S, S)\nend\n\n@acset_type DDS(SchDDS, index=[:nxt])\n\nfₓ = @acset DDS begin\n S = 3\n nxt = [2,3,1]\nend","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"Now if you want to draw a DDS, you might think to draw each state as a vertex and the next relationship as an arrow from one state to the next state. If your intuition selected that representation, you have already discovered a special case of the category of elements","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"elᶠ = elements(fₓ)\ndraw(graph(elᶠ))","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"As you are quite far in your category theoretic training, you are surely suspicious of the idea that you would construct the category of elements of a DDS and get a graph. We have a categorical construction, so your intuition should be saying \"there should be some kind of morphism that goes with this object\". And there is, the Elements of a C-Set X is a graph whose vertices are rows in the tables of X and whose edges are the foreign key relationships in X, along with a graph homomorphism into the schema C. We can draw this using the same color coding convention we used to draw graph homomorphisms.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"draw(elᶠ)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"We can scale up our DDS drawing too.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"Fₓ = @acset DDS begin\n S = 7\n nxt = [2,3,1, 1,7,7,4]\nend\ndraw(elements(Fₓ))","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"A category of elements derived from a C-Set is stored as a C-Set of on a different schema. You can see that it is the data of a graph homomorphism where the codomain graph has vertex and edge labels. The two projections πₑ and πₐ are the components of a natural transformation between graphs viewed as functors into Set. The names are attributes usually of type Symbol.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"to_graphviz(SchElements)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"In the case of a DDS, we have only one object and one morphism in the schema. Since the graph with one edge and one vertices is terminal in Graph, there is only one vertex and edge color being used.","category":"page"},{"location":"generated/sketches/cat_elements/#The-Elements-of-a-Graph-are-its-Vertices-and-Edges","page":"The Category of Elements","title":"The Elements of a Graph are its Vertices and Edges","text":"","category":"section"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"In what might appear as primordial ooze, we can examine the category of elements of a graph. We will look at the commuting triangle graph. Notice how there are 3 vertices and three edges with each edge incident to 2 vertices.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"g = @acset Graph begin\n V = 3\n E = 3\n src = [1,2,1]\n tgt = [2,3,3]\nend\ndraw(g)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"The category of elements has 6 vertices and 6 edges. The 6 vertices come from 3 vertices of type V and 3 vertices of type E. The 6 edges in this graph are 3 src relationships and 3 target relationships.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"elᵍ = elements(g)\ndraw(elᵍ)\n\ng = @acset Graph begin\n V = 6\n E = 7\n src = [1,2,1,3,5,6,4]\n tgt = [2,3,3,5,6,3,4]\nend\ndraw(g)\ndraw(elements(g))","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"Notice that the 3 vertices of type E are interspersed between the 3 vertices of type V and vice versa. You can see that the normal visual syntax for a graph is more compact for the special case of graphs. However the category of elements works for any schema C.","category":"page"},{"location":"generated/sketches/cat_elements/#Generality-of-the-construction","page":"The Category of Elements","title":"Generality of the construction","text":"","category":"section"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"Discrete Dynamical Systems and Graphs are clearly data structures from mathematics and so it would make sense that they have a clean representation in the categorical language. But how about a database schema that comes not from mathematics, but from software engineering. We turn to everyone's favorite database example, the HR database at a fictitious company.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"@present SchCompany(FreeSchema) begin\n (P, D, S)::Ob # Person, Department, Salary\n worksin::Hom(P, D) # Every Person works in a Department\n makes::Hom(P, S) # Every Person makes a Salary\n reportsto::Hom(P, P) # Every Person reports to a Person\n managedby::Hom(D, P) # Every Department is managed by a Person\n leq::Hom(S,S) # Salaries are a finite total order\nend\n\n@acset_type Company(SchCompany, index=[])","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"We can draw a company that has 4 people, 2 departments, and 3 distinct salaries.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"cmpy = @acset Company begin\n P = 4\n D = 2\n S = 3\n worksin = [1,1,2,2]\n makes = [3,1,2,1]\n reportsto = [1, 1,1,3]\n managedby = [1,3]\n leq = [2,3,3]\nend","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"A visualization of the elements of this functor is commonly described as a knowledge graph.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"elᶜ = elements(cmpy)\ndraw(elᶜ)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"The visualization of the category of elements isn't the most compact representation of data, but it is always an option. Once you know how to draw a graph homomorphism as a color-coded graph, you know how to draw any C-Set. The vertices and edges of the domain graph are the rows and fields of the C-Set, and the colors are from the vertices and edges of the schema C, viewed as a graph presenting the category. One thing you lose is the ability to represent path equations in C.","category":"page"},{"location":"generated/sketches/cat_elements/#Reconstructing-the-C-Set-from-its-category-of-elemnts","page":"The Category of Elements","title":"Reconstructing the C-Set from its category of elemnts","text":"","category":"section"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"When looking at the graphical representation of the category of elements, you can see that the vertices are numbered sequentially within their vertex type. This order can be computed with the incident function in Catlab. There are inclusions of all the tables in the database instance into the global vertex set of the knowledge graph representation.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"incident(elᶜ, :, :πₑ)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"The same goes for the edges (arrows) in the category of elements.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"incident(elᶜ, :, :πₐ)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"From this information, you can reassemble the knowledge graph into a database. You use the codomain graph as the schema and then these two projections πₑ and πₐ to recover the instance data.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"cset(T::Type, el::Elements) = begin\n X = T()\n ℓ = Dict{Int, Int}() # this map reverses the inclusions converting global element numbers into per-table numbers\n for ob in parts(el, :Ob)\n obname = el[ob, :nameo]\n eltsob = incident(el, ob, :πₑ)\n pts = add_parts!(X, obname, length(eltsob))\n map(zip(pts, eltsob)) do (i,x)\n ℓ[x] = i\n end\n end\n for h in parts(el, :Hom)\n nameh = el[h, :nameh]\n arrₕ = incident(el, h, :πₐ)\n doms = map(arrₕ) do e\n ℓ[el[e, :src]]\n end\n codoms = map(arrₕ) do e\n ℓ[el[e, :tgt]]\n end\n set_subpart!(X, doms, nameh, codoms)\n end\n return X\nend","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"We can apply this algorithm to our company knowledge graph to recover our original DB.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"cset(Company, elᶜ)\ncmpy == cset(Company, elᶜ)","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"Hopefully you see one reason why graphs are ubiquitous in computer science. Every relational database is isomorphic to a typed graph. You can generate this graph from the database and recover the database from the typed graph. So while knowledge graphs are great for ingesting data when you aren't sure about the structure and useful for some types of computation that involve long paths. You can always build your software on relational databases knowing that you can easily get access to all the graph algorithms by applying the Grothendieck construction.","category":"page"},{"location":"generated/sketches/cat_elements/#The-Slice-Elements-Transform","page":"The Category of Elements","title":"The Slice-Elements Transform","text":"","category":"section"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"An amazing fact about presheaf toposes is that they are closed under taking slices. In the graphs section of this documentation, you can find a description of bipartite and k-partite graphs as a morphisms into a clique. That definition is very mathematically pleasing because it gives you a category of partitioned graphs that are derived from commuting triangles in Graph. However, for application oriented practitioners, the definition of a bipartite graph as \"a graph with two sets of vertices, where all the edges go between the groups with no edges within either group\" is probably more explicit. For example a classic way to get a bipartite graph would be to look at the graph of authors and papers that those authors wrote. People write papers, people do not write people and papers do not write papers so the authorship graph is bipartite. These two equivalent definitions of a bipartite graph are related via an isomorphism you can find on the nlab. It shows that a slice category of [C,Set]/X is isomorphic to [El(X), Set] which is a cateogory of presheaves on a different schema. Catlab knows how to use this idea to turn a category of elements into a schema for a new category of presheaves. The two directions of the isomorphism are not yet implemented.","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"e = @acset Graph begin\n V = 2\n E = 1\n src = 1\n tgt = 2\nend\n\ndraw(elements(e))\n\nSchBipartite = CatElements.presentation(elements(e))[1]\nto_graphviz(SchBipartite)\n\n@acset_type BipartiteGraph(SchBipartite)\nb = @acset BipartiteGraph begin\n V_1 = 3\n V_2 = 2\n E_1 = 5\n src_E_1 = [1,2,3,3,2]\n tgt_E_1 = [1,2,2,1,1]\nend\ndraw(elements(b))","category":"page"},{"location":"generated/sketches/cat_elements/","page":"The Category of Elements","title":"The Category of Elements","text":"As a very advanced exercise, you could try to implement one or both directions of the isomorphism above.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"EditURL = \"../../../literate/graphs/graphs_label.jl\"","category":"page"},{"location":"generated/graphs/graphs_label/#Labeled-Graphs","page":"Labeled Graphs","title":"Labeled Graphs","text":"","category":"section"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"This example demonstrates how to define new C-Sets from existing C-Sets via the example of adding labels to a graph. We treat labels as members of an arbitrary FinSet of labels rather than a data attribute for pedagogical reasons. When you think of graphs where the labels are numbers, colors, or values of some kind, you would want to make them attributes. The motivation for this example is to be the simplest extension to the theory of graphs that you could possibly make.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"using Catlab.Theories, Catlab.CategoricalAlgebra\nusing Catlab.Graphs, Catlab.Graphics\n\nusing Colors\ndraw(g) = to_graphviz(g, node_labels=true, edge_labels=true)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We start with the theory of graphs, which is copied from Catlab.Graphs.BasicGraphs. The two objects are the edges and vertices and we have two functions src,tgt that assign to every edge the source vertex and target vertex respectively. Functors from this category to Set (diagrams in Set of this shape) are category theoretic graphs (directed multigraphs).","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"@present SchGraph(FreeSchema) begin\n V::Ob\n E::Ob\n src::Hom(E,V)\n tgt::Hom(E,V)\nend\n\nto_graphviz(SchGraph)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"To the theory of graphs we want to add a set of labels L and map that assigns to every vertex to its label in L.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"@present SchLGraph <: SchGraph begin\n L::Ob\n label::Hom(V,L)\nend\n\nto_graphviz(SchLGraph)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Catlab will automatically generate all the data structure and algorithms (storing, mutating, serializing, etc.) our LGraphs for us. This snippet declares that the Julia type LGraph should be composed of objects of the functor category SchLGraph → Skel(FinSet), where Skel(FinSet) is the subcategory of Set containing finite sets of form 1:n. We want our Julia type LGraph to inherit from the type AbstractGraph so that we can run graph algorithms on it. And we want the generated data structures to make an index of the maps src, tgt, and label so that looking up the in and outneighbors of vertex is fast and accessing all vertices by label is also fast.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Note: This schema differs from that of LabeledGraph in Catlab.Graphs by making the label type an object (Ob) rather than attribute type (AttrType). In this case, the set of labels can vary from instance to instance and homomorphisms can rename labels; in the other case, the set of labels is fixed by a Julia type, such as Int or Symbol, and label values must be strictly preserved homomorphisms. The graph theory literature does not always distinguish very carefully between these two cases.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"@acset_type LGraph(SchLGraph, index=[:src,:tgt,:label]) <: AbstractGraph","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We need to tell Catlab how to convert our LGraph type into the normal Graph type by taking just the edges and vertices. This could be computed with Functorial Data Migration, but that is left for another sketch.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"to_graph(g::LGraph) = begin\n h = Graph(nparts(g,:V))\n for e in edges(g)\n add_edge!(h, g[e, :src], g[e,:tgt])\n end\n return h\nend","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Graphviz doesn't automatically know how we want to draw the labels, so we have to explicitly provide code that converts them to colors on the vertices. Note that we aren't calling these colored graphs, because that would imply some connectivity constraints on which vertices are allowed to be colored with the same colors. These labels are arbitrary, but we use color to visually encode them.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"GraphvizGraphs.to_graphviz(g::LGraph; kw...) =\n to_graphviz(to_graphviz_property_graph(g; kw...))\n\nfunction GraphvizGraphs.to_graphviz_property_graph(g::LGraph; kw...)\n h = to_graph(g)\n pg = to_graphviz_property_graph(h; kw...)\n vcolors = hex.(range(colorant\"#0021A5\", stop=colorant\"#FA4616\", length=nparts(g, :L)))\n for v in vertices(g)\n l = g[v, :label]\n set_vprops!(pg, v, Dict(:color => \"#$(vcolors[l])\"))\n end\n pg\nend\n\ndraw(G::LGraph) = to_graphviz(G, node_labels=true, edge_labels=true)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Now we can start making some LGraph instances.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"G = @acset LGraph begin\n V = 4\n E = 4\n L = 4\n src = [1,1,2,3]\n tgt = [2,3,4,4]\n label = [1,2,3,4]\nend\n\ndraw(G)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"The graph G has a 1-1 map between vertices and labels. That isn't necessary.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"H = @acset LGraph begin\n V = 4\n E = 4\n L = 3\n src = [1,1,2,3]\n tgt = [2,3,4,4]\n label = [1,2,2,3]\nend\n\ndraw(H)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We can look at some homomorphisms from G to H by their action on the labels or on the vertices.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(G,H) = map(α -> α[:V], homomorphisms(G, H))\nhomsₗ(G,H) = map(α -> α[:L], homomorphisms(G, H))","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"αₗ: G→ H","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsₗ(G,H)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"αᵥ: G→ H","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(G,H)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Note that if we reverse the direction of our homomorphism search, we get fewer matches even though the two LGraphs are isomorphic as graphs. The fact that in H vertex two and three are the same label means we have to send them to the same vertex in G.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(H,G)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We can build some bigger examples like A.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"A = @acset LGraph begin\n V = 6\n E = 7\n L = 3\n src = [1,1,2,3,2,5,4]\n tgt = [2,3,4,4,5,6,6]\n label = [1,2,2,3,2,3]\nend\ndraw(A)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"and B.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"B = @acset LGraph begin\n V = 6\n E = 7\n L = 4\n src = [1,1,2,3,2,5,4]\n tgt = [2,3,4,4,5,6,6]\n label = [1,2,4,3,2,3]\nend\ndraw(B)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"The morphisms from A to B and B to A are also different, showing how the labels affect the structure in this category.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(A,B)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"There are more morphisms from B to A than A to B.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(B,A)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"There are two automorphisms on A","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(A,A)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"And two automorphisms on B","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homsᵥ(B,B)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"But if we forget about the labels and look at the automorphisms of the underlying graph, we get more automorphisms!","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"A₀ = to_graph(A)\nhomsᵥ(A₀, A₀)","category":"page"},{"location":"generated/graphs/graphs_label/#Limits-and-Composition-by-Multiplication","page":"Labeled Graphs","title":"Limits and Composition by Multiplication","text":"","category":"section"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Catlab has an implementation of limits for any C-Sets over any schema. So, we can just ask about labeled graphs. Notice that we get more distinct colors in the product than in either initial graph. This is because the labels of the product are pairs of labels from the factors. If G has n colors and H has m colors G×H will have n×m colors.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"draw(apex(product(G,G)))","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"The graph above looks weirdly disconnected and probably wasn't what you expected to see as the product. When we compose with products, we often want to add the reflexive edges in order to get the expected notion of product.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"add_loops!(G::LGraph) = begin\n for v in parts(G,:V)\n add_edge!(G, v,v)\n end\n return G\nend\nadd_loops(G::LGraph) = add_loops!(copy(G))\n\nGᵣ = add_loops(G)\nP = apex(product(Gᵣ, G))\ndraw(apex(product(Gᵣ, G)))","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We can look at the shape of commuting triangle, which is our favorite 3-vertex graph.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"T = @acset LGraph begin\n V = 3\n E = 3\n L = 3\n src = [1,1,2]\n tgt = [2,3,3]\n label = [1,2,3]\nend\nTᵣ = add_loops(T)\ndraw(Tᵣ)\n\nE = @acset LGraph begin\n V = 2\n E = 1\n L = 2\n src = [1]\n tgt = [2]\n label = [1,2]\nend\nEᵣ = add_loops(E)\ndraw(Eᵣ)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We can draw the product of the edge graph and the triangle graph to get the shape of a triangular prism. You can view this product as extruding Tᵣ along Eᵣ. Catlab provides a ReflexiveGraph as a type that handles these self-loops more intelligently than we are here. Graphviz struggles with the layout here because the product graph will include edges that are a step in both directions. This blog post does a good job explaining products in differnt kinds of graph categories.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"draw(apex(product(Tᵣ,Eᵣ)))\nlegs(product(Tᵣ, Eᵣ))[1][:V] |> collect","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Another limit is the pullback. If you have a cospan, which is a diagram of the shape X ⟶ A ⟵ Y, you can pull back one arrow along the other by solving a system of equations.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"PB₂₂ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[2]);\ndraw(apex(PB₂₂))","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Note that the pullback depends not only on X,A,Y but also on the two arrows. You can play around with the choice of morphisms to gain an intuition of how the pullback depends on the morphisms.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"PB₂₃ = pullback(homomorphisms(Tᵣ,Eᵣ)[2],homomorphisms(Tᵣ,Eᵣ)[3]);\ndraw(apex(PB₂₃))","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"By constructions, the pullback is always a subobject (monic homomorphism) into the product. Catlab can enumerate all such monoic homs.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"homomorphisms(apex(PB₂₂), apex(product(Tᵣ,Tᵣ)), monic=true) |> length","category":"page"},{"location":"generated/graphs/graphs_label/#Colimits-and-Composition-by-Glueing","page":"Labeled Graphs","title":"Colimits and Composition by Glueing","text":"","category":"section"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"The dual concept to limits is colimits and if limits have vibes of taking all pairs that satisfy certain constraints, colimits have the vibes of designers just gluing stuff together to make it work.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"In order to illustrate this we will be gluing triangles together to make a mesh. We start by defining the point X, which is the shape of the boundary along which we will glue and the morphism ℓ₁, which is the place in T that we consider as the boundary.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"X = @acset LGraph begin\n E = 0\n V = 1\n L = 3\n label=[2]\nend\nℓ₁ = ACSetTransformation(X,T, V=[2],L=1:3)\ndraw(X)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We have to check that the morphism is valid before we go and compute out pushout.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"is_natural(ℓ₁)\nP = pushout(ℓ₁, ℓ₁)\ndraw(apex(P))","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"Now we want to repeat the gluing process to get a bigger mesh. So we are going to need a bigger interface.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"I = @acset LGraph begin\n V = 2\n L = 3\n label = [1,1]\nend\ndraw(I)","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"We have to specify how this interface embeds into both of the things we want to glue. In this case we are gluing a copy of P onto itself.","category":"page"},{"location":"generated/graphs/graphs_label/","page":"Labeled Graphs","title":"Labeled Graphs","text":"ll = ACSetTransformation(I, apex(P), V=[3,5], L =[3,1,2])\nis_natural(ll)\nlr = ACSetTransformation(I, apex(P), V=[1,4], L =[1,3,2])\nis_natural(lr)\nP₂ = pushout(ll, lr);\ndraw(apex(P₂))","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"EditURL = \"../../../literate/wiring_diagrams/wd_cset.jl\"","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/#Wiring-Diagrams-as-Attributed-C-Sets","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"","category":"section"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"Catlab supports many different flavors of diagrammatic syntax. These support the different combinatorial data structures that we use for representing categorical constructions. We will discuss DirectedWiringDiagrams, UndirectedWiringDiagrams, and CPortGraphs in this document.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"using Catlab.Theories, Catlab.CategoricalAlgebra\nusing Catlab.WiringDiagrams, Catlab.Programs, Catlab.Graphics\nusing Catlab.Graphics: Graphviz\n\ndraw(d::WiringDiagram) = to_graphviz(d,\n orientation=LeftToRight,\n labels=true, label_attr=:xlabel,\n node_attrs=Graphviz.Attributes(\n :fontname => \"Courier\",\n ),\n edge_attrs=Graphviz.Attributes(\n :fontname => \"Courier\",\n )\n)\n\ndraw(uwd::AbstractUWD) = to_graphviz(uwd, junction_labels=:variable, box_labels=:name)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/#Directed-Wiring-Diagrams","page":"Wiring Diagrams as Attributed C-Sets","title":"Directed Wiring Diagrams","text":"","category":"section"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"DWDs are used to represent the morphisms in a symmetric monoidal category. You can get started by presenting a FreeSymmetricMonoidalCategory with the @present macro.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"@present P(FreeSymmetricMonoidalCategory) begin\n (A,B,C,D)::Ob\n f::Hom(A,B)\n g::Hom(B,A)\n h::Hom(A⊗B, C)\n k::Hom(C,D⊗A)\nend\ngenerators(P)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"These presentations are very syntactic objects and expose an API for manipulating expressions.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"for g in generators(P)\n \"$g is a $(gat_typeof(g)) with arguments $(gat_type_args(g))\"\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"The gat_typeof function computes the algebraic type of a term by analogy to Base.typeof which computes the Julia type of a value.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"homs_P = filter(generators(P)) do g\n gat_typeof(g) == :Hom\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"When the term is a Hom, you can get the domain and codomain of the morphism with the dom and codom functions.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"map(homs_P) do f\n \"$f: $(dom(f)) → $(codom(f))\"\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"With the presentation you can build up morphism expressions using a formula syntax.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"P[:h]⋅P[:k]","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"This syntactic API is useful for manipulating terms in an arbitrary GAT and is the formal language of Catlab for representing and manipulating algebraic structures. However, when we want to work with big expressions in an SMC, the tree structure inherent to formulas is too verbose, and we want to move to a port-graph structure called DirectedWiringDiagrams. This gives us the benefits of combinatorial data structures like graphs with the right expressional power for representing the morphisms in an SMC.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"wd = @program P (a::A, b::B) begin\n c = h(a,b)\n return k(c)\nend\n\ndraw(wd)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"Catlab gives you the tools for drawing wiring diagrams. Visualization of wiring diagrams is the oldest part of Catlab and the original motivation for its development. The @program macro allows you to define wiring diagrams using a syntax that feels like Julia code.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"wd = @program P (a::A, b::B) begin\n c = h(a,b)\n d,a₁ = k(c)\n return d, f(a₁)\nend\ndraw(wd)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"The input wires are declared as arguments to the program, and the output wires are declared as returns from the function. Variables that are not consumed or by another function or returned by the program are automatically dropped.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"wd = @program P (a::A, b::B) begin\n c = h(a,b)\n d,a₁ = k(c)\n return f(a₁)\nend\ndraw(wd)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"You can copy a value by using it more than once. This is visualized as a wire being split into two wires.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"wd = @program P (b::B) begin\n h(g(b),b)\nend\ndraw(wd)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"You can visualize the copy and delete morphisms explicitly with the add_junctions function. The dots with one wire input and multiple outputs are copying values and dots with no wires out are deletions (discarding values). Not all instances of a SymmetricMonoidalCategory support copy and delete, for example, in manufacturing you can't duplicate a resource, and in chemistry you can't discard species. Catlab would enforce that when you tried to interpret the wiring diagram in a specific SMC.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"wd = @program P (b::B) begin\n c = h(g(b),b)\n d, a₁ = k(c)\n return f(a₁)\nend\ndraw(add_junctions(wd))","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"For more details about working with wiring diagrams in Catlab, you should look at the other vignettes in this section which explain how wiring diagrams interact with SMC expressions and the basics of constructing and manipulation wiring diagrams.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/#Diagrams-as-C-Sets","page":"Wiring Diagrams as Attributed C-Sets","title":"Diagrams as C-Sets","text":"","category":"section"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"The underlying data of a wiring diagram is combinatorial. That means we can represent it as a C-Set","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"wd.diagram","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"Ok, there is a lot in there. The columns with integer entries are the combinatorial data encoding the connectivity of the wiring diagram. The columns with Symbols in them are encoding the labels for the diagram, the value of a box is the content of the box. Ports have types and wires have values. When we define the wiring diagram with the @program macro, we get a diagram that has labels and types, but no values. These values are initialized to nothing, but could be filled with values to be carried down the wires in an application.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"The schema of for wiring diagrams is called SchAttributedWiringDiagrams and is a little overwhelming, so we can explore how to build it up with C-Set schema inheritance.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"to_graphviz(SchAttributedWiringDiagram)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"From the file Catlab/src/WiringDiagrams/Directed.jl","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"@present SchWiringDiagram(FreeSchema) begin\n Box::Ob\n (InPort, OutPort, OuterInPort, OuterOutPort)::Ob\n (Wire, InWire, OutWire, PassWire)::Ob\n\n src::Hom(Wire, OutPort)\n tgt::Hom(Wire, InPort)\n in_src::Hom(InWire, OuterInPort)\n in_tgt::Hom(InWire, InPort)\n out_src::Hom(OutWire, OutPort)\n out_tgt::Hom(OutWire, OuterOutPort)\n pass_src::Hom(PassWire, OuterInPort)\n pass_tgt::Hom(PassWire, OuterOutPort)\n\n in_port_box::Hom(InPort, Box)\n out_port_box::Hom(OutPort, Box)\nend\n\n@abstract_acset_type AbstractWiringDiagram <: AbstractGraph\n\n@present SchTypedWiringDiagram <: SchWiringDiagram begin\n PortValue::AttrType\n in_port_type::Attr(InPort, PortValue)\n out_port_type::Attr(OutPort, PortValue)\n outer_in_port_type::Attr(OuterInPort, PortValue)\n outer_out_port_type::Attr(OuterOutPort, PortValue)\nend\n\n@present SchAttributedWiringDiagram <: SchTypedWiringDiagram begin\n WireValue::AttrType\n BoxValue::AttrType\n BoxType::AttrType\n\n value::Attr(Box, BoxValue)\n box_type::Attr(Box, BoxType)\n wire_value::Attr(Wire, WireValue)\n in_wire_value::Attr(InWire, WireValue)\n out_wire_value::Attr(OutWire, WireValue)\n pass_wire_value::Attr(PassWire, WireValue)\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"The bare minimum diagram language is:","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"to_graphviz(SchWiringDiagram)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"And then you can add back in the types.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"to_graphviz(SchTypedWiringDiagram)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"Layout is hard, so if you want to understand the SchAttributedWiringDiagrams, you should do the layout by hand as an exercise.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"We can create our own version of the theory of DWDs to see how it works:","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"@present MySchWiringDiagram(FreeSchema) begin\n Box::Ob\n (InPort, OutPort, OuterInPort, OuterOutPort)::Ob\n (Wire, InWire, OutWire, PassWire)::Ob\n\n src::Hom(Wire, OutPort)\n tgt::Hom(Wire, InPort)\n in_src::Hom(InWire, OuterInPort)\n in_tgt::Hom(InWire, InPort)\n out_src::Hom(OutWire, OutPort)\n out_tgt::Hom(OutWire, OuterOutPort)\n pass_src::Hom(PassWire, OuterInPort)\n pass_tgt::Hom(PassWire, OuterOutPort)\n\n in_port_box::Hom(InPort, Box)\n out_port_box::Hom(OutPort, Box)\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"If your application of wiring diagrams needs to attach numeric or textual information to the boxes of a wiring diagram, you would extend the SchWiringDiagram with the attributes that you need. That will give you a custom data structure that has those fields. One of the goals of Catlab is to make it so much easier to generate custom data structures that interoperate, that you don't need to create generic structures that can be used for many purposes. Just snap your fingers and create a new structure perfectly tailored to your needs, when your needs change, snap again to get a new version of that structure.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"The @acset_type macro does the hard work of generating the data structure and accessors and mutators for you. The form of this call is @acset_type NewStructName(Schema, index=[morphisms in Schema]) <: Supertype. You should index any morphism where you need to use incident frequently. For wiring diagrams you will often want to know what all the wires that are incident to a port.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"@acset_type MyWiringDiagramACSet(MySchWiringDiagram,\n index=[:src, :tgt, :in_src, :in_tgt, :out_src, :out_tgt, :pass_src, :pass_tgt]) <: WiringDiagrams.DirectedWiringDiagrams.AbstractWiringDiagram","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"We get the @acset macro from Catlab and can create DWDs by hand. It is very tedious, which is why the @program macro exists!","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"md = @acset MyWiringDiagramACSet begin\n Box = 3\n InPort = 6\n OutPort = 3\n Wire = 3\n src = [1,2,3]\n tgt = [3,4,5]\n in_port_box = [1,1,2,2,3,3]\n out_port_box = [1,2,3]\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/#Undirected-Wiring-Diagrams","page":"Wiring Diagrams as Attributed C-Sets","title":"Undirected Wiring Diagrams","text":"","category":"section"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"A much simpler structure than DWDs are known as undirected wiring diagrams. They are called undirected because ports boxes have one set of ports that aren't divided into inputs and outputs, and the wires are undirected. Wires connect junctions to ports (which live on boxes).","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"to_graphviz(SchUWD)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"These UWDs are combinatorial syntax for relations. The junctions are variables and the boxes are the relations. A relation R ⊆ X × Y has two ports one for the value of X and one for the value of Y. The expression R(x:X, y:Y) says to connect the X port of R to the junction for the variable x, and the Y port of R to the y variable junction. If two ports are attached to the same junction, then you have a constraint that those values must be equal. The outer ports are the components of the final relation. For example the following UWD encodes the relation {(x,y,z) | R(x,y) and S(y,z) for all x∈X, y∈Y, z∈Z}.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"uwd = @relation (x, y, z) begin\n R(x,y)\n S(y,z)\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"These UWDs are drawn with circular boxes and undirected wires. Note that since all wires go from junction to port, they are not symmetric wires.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"draw(uwd)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"By adding more relations we can get bigger relations.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"uwd₂ = @relation (x, z) begin\n R(x,y)\n S(y,z)\n T(x,z,y)\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"Not all of the junctions have to be exposed to the outside world. Note that there is no distinction between arguments and return values in the relation macro. This is because relations are inherently undirected, unlike functions.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"draw(uwd₂)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/#Circular-Port-Graphs","page":"Wiring Diagrams as Attributed C-Sets","title":"Circular Port Graphs","text":"","category":"section"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"CPGs are the natural data structure for representing process of interconnected systems that share information along wires, but send different information to their different neighbors.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"to_graphviz(SchCPortGraph)","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"They are also a kind of CSet, so we can use the @acset macro to construct them.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"cpg = @acset CPortGraph begin\n Box = 3\n Port = 6\n Wire = 5\n\n box = [1,1,2,2,3,3]\n src = [1,2,5,2,6]\n tgt = [3,4,2,4,1]\nend","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"the layout for CPGs is not great with graphviz.","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"to_graphviz(cpg, port_labels=true, graph_attrs=Dict(\"nodesep\"=>\"2\", \"ranksep\"=>\"2\"))","category":"page"},{"location":"generated/wiring_diagrams/wd_cset/","page":"Wiring Diagrams as Attributed C-Sets","title":"Wiring Diagrams as Attributed C-Sets","text":"Almost every application of graphs in computer science could be better served by using one of these extensions to the basic graph data structure.","category":"page"},{"location":"apis/categorical_algebra/#categorical_algebra","page":"Categorical algebra","title":"Categorical algebra","text":"","category":"section"},{"location":"apis/categorical_algebra/#Sets-and-Relations","page":"Categorical algebra","title":"Sets and Relations","text":"","category":"section"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The following APIs implement FinSet, the category of Finite Sets (actually the skeleton of FinSet). The objects of this category are natural numbers where n represents a set with n elements. The morphisms are functions between such sets. We use the skeleton of FinSet in order to ensure that all sets are finite and morphisms can be stored using lists of integers. Finite relations are built out of FinSet and can be used to do some relational algebra.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Modules = [\n CategoricalAlgebra.Sets,\n CategoricalAlgebra.FinSets,\n CategoricalAlgebra.FinRelations,\n ]\nPrivate = false","category":"page"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Sets","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Sets","text":"Category of (possibly infinite) sets and functions.\n\nThis module defines generic types for the category of sets (SetOb, SetFunction), as well as a few basic concrete types, such as a wrapper type to view Julia types as sets (TypeSet). Extensive support for finite sets is provided by another module, FinSets.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Sets.ConstantFunction","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Sets.ConstantFunction","text":"Function in Set taking a constant value.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Sets.PredicatedSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Sets.PredicatedSet","text":"Set defined by a predicate (boolean-valued function) on a Julia data type.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Sets.SetFunction","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Sets.SetFunction","text":"Abstract type for morphism in the category Set.\n\nEvery instance of SetFunction{<:SetOb{T},<:SetOb{T′}} is callable with elements of type T, returning an element of type T′.\n\nNote: This type would be better called simply Function but that name is already taken by the base Julia type.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Sets.SetOb","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Sets.SetOb","text":"Abstract type for object in the category Set.\n\nThe type parameter T is the element type of the set.\n\nNote: This type is more abstract than the built-in Julia types AbstractSet and Set, which are intended for data structures for finite sets. Those are encompassed by the subtype FinSet.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Sets.TypeSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Sets.TypeSet","text":"A Julia data type regarded as a set.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.Ob-Union{Tuple{TypeCat{T}}, Tuple{T}} where T","page":"Categorical algebra","title":"AlgebraicInterfaces.Ob","text":"Forgetful functor Ob: Cat → Set.\n\nSends a category to its set of objects and a functor to its object map.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets","text":"The category of finite sets and functions, and its skeleton.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.FinDomFunction","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.FinDomFunction","text":"Function out of a finite set.\n\nThis class of functions is convenient because it is exactly the class that can be represented explicitly by a vector of values from the codomain.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.FinFunction","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.FinFunction","text":"Function between finite sets.\n\nThe function can be defined implicitly by an arbitrary Julia function, in which case it is evaluated lazily, or explictly by a vector of integers. In the vector representation, the function (1↦1, 2↦3, 3↦2, 4↦3), for example, is represented by the vector [1,3,2,3].\n\nFinFunctions can be constructed with or without an explicitly provided codomain. If a codomain is provided, by default the constructor checks it is valid.\n\nThis type is mildly generalized by FinDomFunction.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.FinSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.FinSet","text":"Finite set.\n\nA finite set has abstract type FinSet{S,T}. The second type parameter T is the element type of the set and the first parameter S is the collection type, which can be a subtype of AbstractSet or another Julia collection type. In addition, the skeleton of the category FinSet is the important special case S = Int. The set 1n is represented by the object FinSet(n) of type FinSet{Int,Int}.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.HashJoin","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.HashJoin","text":"Hash join algorithm.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.JoinAlgorithm","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.JoinAlgorithm","text":"Algorithm for limit of cospan or multicospan with feet being finite sets.\n\nIn the context of relational databases, such limits are called joins. The trivial join algorithm is NestedLoopJoin, which is algorithmically equivalent to the generic algorithm ComposeProductEqualizer. The algorithms HashJoin and SortMergeJoin are usually much faster. If you are unsure what algorithm to pick, use SmartJoin.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.NestedLoopJoin","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.NestedLoopJoin","text":"Nested-loop join algorithm.\n\nThis is the naive algorithm for computing joins.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.SmartJoin","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.SmartJoin","text":"Meta-algorithm for joins that attempts to pick an appropriate algorithm.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.SortMergeJoin","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.SortMergeJoin","text":"Sort-merge join algorithm.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.SubFinSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.SubFinSet","text":"Subset of a finite set.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.SubOpBoolean","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.SubOpBoolean","text":"Algorithm to compute subobject operations using elementwise boolean logic.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.TabularLimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.TabularLimit","text":"Limit of finite sets viewed as a table.\n\nAny limit of finite sets can be canonically viewed as a table (TabularSet) whose columns are the legs of the limit cone and whose rows correspond to elements of the limit object. To construct this table from an already computed limit, call TabularLimit(::AbstractLimit; ...). The column names of the table are given by the optional argument names.\n\nIn this tabular form, applying the universal property of the limit is trivial since it is just tupling. Thus, this representation can be useful when the original limit algorithm does not support efficient application of the universal property. On the other hand, this representation has the disadvantage of generally making the element type of the limit set more complicated.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.TabularSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.TabularSet","text":"Finite set whose elements are rows of a table.\n\nThe underlying table should be compliant with Tables.jl. For the sake of uniformity, the rows are provided as named tuples, which assumes that the table is not \"extremely wide\". This should not be a major limitation in practice but see the Tables.jl documentation for further discussion.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.VarFunction","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.VarFunction","text":"Data type for a morphism of VarSet{T}s. Note we can equivalently view these as morphisms [n]+T -> [m]+T fixing T or as morphisms [n] -> [m]+T, in the typical Kleisli category yoga. \n\nCurrently, domains are treated as VarSets. The codom field is treated as a FinSet{Int}. Note that the codom accessor gives a VarSet while the codom field is just that VarSet's FinSet of AttrVars. This could be generalized to being FinSet{Symbol} to allow for symbolic attributes. (Likewise, AttrVars will have to wrap Any rather than Int)\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.VarSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.VarSet","text":"Control dispatch in the category of VarFunctions\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#ACSets.PreimageCaches.preimage-Tuple{Catlab.CategoricalAlgebra.Sets.IdentityFunction, Any}","page":"Categorical algebra","title":"ACSets.PreimageCaches.preimage","text":"The preimage (inverse image) of the value y in the codomain.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinSets.is_indexed-Tuple{SetFunction}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinSets.is_indexed","text":"Whether the given function is indexed, i.e., supports efficient preimages.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinRelations","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinRelations","text":"The category of finite sets and relations, and its skeleton.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinRelations.BoolRig","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinRelations.BoolRig","text":"The rig of booleans.\n\nThis struct is needed because in base Julia, the product of booleans is another boolean, but the sum of booleans is coerced to an integer: true + true == 2.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinRelations.FinRel","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinRelations.FinRel","text":"Object in the category of finite sets and relations.\n\nSee also: FinSet.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinRelations.FinRelation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinRelations.FinRelation","text":"Binary relation between finite sets.\n\nA morphism in the category of finite sets and relations. The relation can be represented implicitly by an arbitrary Julia function mapping pairs of elements to booleans or explicitly by a matrix (dense or sparse) taking values in the rig of booleans (BoolRig).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinRelations.FinRelationCallable","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinRelations.FinRelationCallable","text":"Relation in FinRel defined by a callable Julia object.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinRelations.FinRelationMatrix","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinRelations.FinRelationMatrix","text":"Relation in FinRel represented by a boolean matrix.\n\nBoolean matrices are also known as logical matrices or relation matrices.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Free-Diagrams,-Limits,-and-Colimits","page":"Categorical algebra","title":"Free Diagrams, Limits, and Colimits","text":"","category":"section"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The following modules define free diagrams in an arbitrary category and specify limit and colimit cones over said diagrams. Thes constructions enjoy the fullest support for FinSet and are used below to define presheaf categories as C-Sets. The general idea of these functions is that you set up a limit computation by specifying a diagram and asking for a limit or colimit cone, which is returned as a struct containing the apex object and the leg morphisms. This cone structure can be queried using the functions apex and legs. Julia's multiple dispatch feature is heavily used to specialize limit and colimit computations for various diagram shapes like product/coproduct and equalizer/coequalizer. As a consumer of this API, it is highly recommended that you use multiple dispatch to specialize your code on the diagram shape whenever possible.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Modules = [\n CategoricalAlgebra.FreeDiagrams,\n CategoricalAlgebra.Limits,\n ]\nPrivate = false","category":"page"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams","text":"Free diagrams in a category.\n\nA free diagram in a category is a diagram whose shape is a free category. Examples include the empty diagram, pairs of objects, discrete diagrams, parallel pairs, composable pairs, and spans and cospans. Limits and colimits are most commonly taken over free diagrams.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.BipartiteFreeDiagram","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.BipartiteFreeDiagram","text":"A free diagram with a bipartite structure.\n\nSuch diagrams include most of the fixed shapes, such as spans, cospans, and parallel morphisms. They are also the generic shape of diagrams for limits and colimits arising from undirected wiring diagrams. For limits, the boxes correspond to vertices in V₁ and the junctions to vertices in V₂. Colimits are dual.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.BipartiteFreeDiagram-Union{Tuple{Functor{<:Category{Int64, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where Hom}}, Tuple{Hom}, Tuple{Ob}} where {Ob, Hom}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.BipartiteFreeDiagram","text":"Convert a free diagram to a bipartite free diagram.\n\nReduce a free diagram to a free bipartite diagram with the same limit (the default, colimit=false) or the same colimit (colimit=true). The reduction is essentially the same in both cases, except for the choice of where to put isolated vertices, where we follow the conventions described at cone_objects and cocone_objects. The resulting object is a bipartite free diagram equipped with maps from the vertices of the bipartite diagram to the vertices of the original diagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.ComposableMorphisms","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.ComposableMorphisms","text":"Composable morphisms in a category.\n\nComposable morphisms are a sequence of morphisms in a category that form a path in the underlying graph of the category.\n\nFor the common special case of two morphisms, see ComposablePair.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair","text":"Pair of composable morphisms in a category.\n\nComposable pairs are a common special case of ComposableMorphisms.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.Cospan","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.Cospan","text":"Cospan of morphisms in a category.\n\nA common special case of Multicospan. See also Span.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.DiscreteDiagram","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.DiscreteDiagram","text":"Discrete diagram: a diagram with no non-identity morphisms.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.FixedShapeFreeDiagram","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.FixedShapeFreeDiagram","text":"Abstract type for free diagram of fixed shape.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.Multicospan","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.Multicospan","text":"Multicospan of morphisms in a category.\n\nA multicospan is like a Cospan except that it may have a number of legs different than two. A limit of this shape is a pullback.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.Multispan","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.Multispan","text":"Multispan of morphisms in a category.\n\nA multispan is like a Span except that it may have a number of legs different than two. A colimit of this shape is a pushout.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.ParallelMorphisms","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.ParallelMorphisms","text":"Parallel morphims in a category.\n\nParallel morphisms are just morphisms with the same domain and codomain. A (co)limit of this shape is a (co)equalizer.\n\nFor the common special case of two morphisms, see ParallelPair.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.ParallelPair","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.ParallelPair","text":"Pair of parallel morphisms in a category.\n\nA common special case of ParallelMorphisms.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.Span","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.Span","text":"Span of morphims in a category.\n\nA common special case of Multispan. See also Cospan.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.apex-Tuple{Multispan}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.apex","text":"Apex of multispan or multicospan.\n\nThe apex of a multi(co)span is the object that is the (co)domain of all the legs.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.bundle_legs-Tuple{Multispan, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.bundle_legs","text":"Bundle together legs of a multi(co)span.\n\nFor example, calling bundle_legs(span, SVector((1,2),(3,4))) on a multispan with four legs gives a span whose left leg bundles legs 1 and 2 and whose right leg bundles legs 3 and 4. Note that in addition to bundling, this function can also permute legs and discard them.\n\nThe bundling is performed using the universal property of (co)products, which assumes that these (co)limits exist.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.cocone_objects-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.cocone_objects","text":"Objects in diagram that will have explicit legs in colimit cocone.\n\nSee also: cone_objects.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.cone_objects-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.cone_objects","text":"Objects in diagram that will have explicit legs in limit cone.\n\nIn category theory, it is common practice to elide legs of limit cones that can be computed from other legs, especially for diagrams of certain fixed shapes. For example, when it taking a pullback (the limit of a cospan), the limit object is often treated as having two projections, rather than three. This function encodes such conventions by listing the objects in the diagram that will have corresponding legs in the limit object created by Catlab.\n\nSee also: cocone_objects.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.diagram_type","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.diagram_type","text":"Given a diagram in a category C, return Julia type of objects and morphisms in C as a tuple type of form TupleObHom.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.feet-Tuple{Multispan}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.feet","text":"Feet of multispan or multicospan.\n\nThe feet of a multispan are the codomains of the legs.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.left-Tuple{Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.left","text":"Left leg of span or cospan.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.legs-Tuple{Multispan}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.legs","text":"Legs of multispan or multicospan.\n\nThe legs are the morphisms comprising the multi(co)span.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.right-Tuple{Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.right","text":"Right leg of span or cospan.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits","text":"Limits and colimits in a category.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.AbstractColimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.AbstractColimit","text":"Abstract type for colimit in a category.\n\nThe standard concrete subtype is Colimit, although for computational reasons certain categories may use different subtypes to include extra data.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.AbstractLimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.AbstractLimit","text":"Abstract type for limit in a category.\n\nThe standard concrete subtype is Limit, although for computational reasons certain categories may use different subtypes to include extra data.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.Colimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.Colimit","text":"Colimit in a category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.ColimitAlgorithm","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.ColimitAlgorithm","text":"Algorithm for computing colimits.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.ComposeCoproductCoequalizer","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.ComposeCoproductCoequalizer","text":"Compute pushout by composing a coproduct with a coequalizer.\n\nSee also: ComposeProductEqualizer.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.ComposeProductEqualizer","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.ComposeProductEqualizer","text":"Compute pullback by composing a product with an equalizer.\n\nSee also: ComposeCoproductCoequalizer.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.Limit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.Limit","text":"Limit in a category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.LimitAlgorithm","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.LimitAlgorithm","text":"Algorithm for computing limits.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.SpecializeColimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.SpecializeColimit","text":"Meta-algorithm that reduces general colimits to common special cases.\n\nDual to SpecializeLimit.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.SpecializeLimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.SpecializeLimit","text":"Meta-algorithm that reduces general limits to common special cases.\n\nReduces limits of free diagrams that happen to be discrete to products. If this fails, fall back to the given algorithm (if any).\n\nTODO: Reduce free diagrams that are (multi)cospans to (wide) pullbacks.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.ToBipartiteColimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.ToBipartiteColimit","text":"Compute a colimit by reducing the diagram to a free bipartite diagram.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.ToBipartiteLimit","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.ToBipartiteLimit","text":"Compute a limit by reducing the diagram to a free bipartite diagram.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FreeDiagrams.apex-Tuple{AbstractLimit}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FreeDiagrams.apex","text":"Synonymous with ob in the case of Limits, but present here to allow a Limit to be implicitly treated like a Multispan.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.coimage-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.coimage","text":"https://en.wikipedia.org/wiki/Coimage\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.colimit-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.colimit","text":"Colimit of a diagram.\n\nTo define colimits in a category with objects Ob, override the method colimit(::FreeDiagram{Ob}) for general colimits or colimit(::D) with suitable type D <: FixedShapeFreeDiagram{Ob} for colimits of specific shape, such as coproducts or coequalizers.\n\nSee also: limit\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.epi_mono-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.epi_mono","text":"The image and coimage are isomorphic. We get this isomorphism using univeral properties.\n\n CoIm′ ╌╌> I ↠ CoIm\n ┆ ⌟ |\n v v\n I ⟶ R ↩ Im\n | ┆\n v ⌜ v\n R ╌╌> Im′\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.image-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.image","text":"https://en.wikipedia.org/wiki/Image(categorytheory)#Second_definition\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.limit-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.limit","text":"Limit of a diagram.\n\nTo define limits in a category with objects Ob, override the method limit(::FreeDiagram{Ob}) for general limits or limit(::D) with suitable type D <: FixedShapeFreeDiagram{Ob} for limits of specific shape, such as products or equalizers.\n\nSee also: colimit\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.pullback-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.pullback","text":"Pullback of a pair of morphisms with common codomain.\n\nTo implement for a type T, define the method limit(::Cospan{T}) and/or limit(::Multicospan{T}) or, if you have already implemented products and equalizers, rely on the default implementation.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.pushout-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.pushout","text":"Pushout of a pair of morphisms with common domain.\n\nTo implement for a type T, define the method colimit(::Span{T}) and/or colimit(::Multispan{T}) or, if you have already implemented coproducts and coequalizers, rely on the default implementation.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.coequalizer-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.Theories.coequalizer","text":"Coequalizer of morphisms with common domain and codomain.\n\nTo implement for a type T, define the method colimit(::ParallelPair{T}) or colimit(::ParallelMorphisms{T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.copair-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.Theories.copair","text":"Copairing of morphisms: universal property of coproducts/pushouts.\n\nTo implement for coproducts of type T, define the method universal(::BinaryCoproduct{T}, ::Cospan{T}) and/or universal(::Coproduct{T}, ::Multicospan{T}) and similarly for pushouts.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.coproduct-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.Theories.coproduct","text":"Coproduct of objects.\n\nTo implement for a type T, define the method colimit(::ObjectPair{T}) and/or colimit(::DiscreteDiagram{T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.create-Tuple{T} where T","page":"Categorical algebra","title":"Catlab.Theories.create","text":"Unique morphism out of an initial object.\n\nTo implement for a type T, define the method universal(::Initial{T}, ::SMulticospan{0,T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.delete-Tuple{T} where T","page":"Categorical algebra","title":"Catlab.Theories.delete","text":"Unique morphism into a terminal object.\n\nTo implement for a type T, define the method universal(::Terminal{T}, ::SMultispan{0,T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.equalizer-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.Theories.equalizer","text":"Equalizer of morphisms with common domain and codomain.\n\nTo implement for a type T, define the method limit(::ParallelPair{T}) and/or limit(::ParallelMorphisms{T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.factorize-Tuple{Equalizer, Any}","page":"Categorical algebra","title":"Catlab.Theories.factorize","text":"Factor morphism through (co)equalizer, via the universal property.\n\nTo implement for equalizers of type T, define the method universal(::Equalizer{T}, ::SMultispan{1,T}). For coequalizers of type T, define the method universal(::Coequalizer{T}, ::SMulticospan{1,T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.initial-Tuple{Type}","page":"Categorical algebra","title":"Catlab.Theories.initial","text":"Initial object.\n\nTo implement for a type T, define the method colimit(::EmptyDiagram{T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.pair-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.Theories.pair","text":"Pairing of morphisms: universal property of products/pullbacks.\n\nTo implement for products of type T, define the method universal(::BinaryProduct{T}, ::Span{T}) and/or universal(::Product{T}, ::Multispan{T}) and similarly for pullbacks.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.product-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.Theories.product","text":"Product of objects.\n\nTo implement for a type T, define the method limit(::ObjectPair{T}) and/or limit(::DiscreteDiagram{T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.terminal-Tuple{Type}","page":"Categorical algebra","title":"Catlab.Theories.terminal","text":"Terminal object.\n\nTo implement for a type T, define the method limit(::EmptyDiagram{T}).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.Theories.universal","page":"Categorical algebra","title":"Catlab.Theories.universal","text":"universal(lim,cone)\n\nUniversal property of (co)limits.\n\nCompute the morphism whose existence and uniqueness is guaranteed by the universal property of (co)limits.\n\nSee also: limit, colimit.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.@cartesian_monoidal_instance-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.@cartesian_monoidal_instance","text":"Define cartesian monoidal structure using limits.\n\nImplements an instance of ThCartesianCategory assuming that finite products have been implemented following the limits interface.\n\n\n\n\n\n","category":"macro"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Limits.@cocartesian_monoidal_instance-Tuple{Any, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Limits.@cocartesian_monoidal_instance","text":"Define cocartesian monoidal structure using colimits.\n\nImplements an instance of ThCocartesianCategory assuming that finite coproducts have been implemented following the colimits interface.\n\n\n\n\n\n","category":"macro"},{"location":"apis/categorical_algebra/#Categories","page":"Categorical algebra","title":"Categories","text":"","category":"section"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Modules = [\n CategoricalAlgebra.Categories,\n CategoricalAlgebra.FinCats,\n]","category":"page"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories","text":"2-category of categories, functors, and natural transformations.\n\nCategories in mathematics appear in the large, often as categories of sets with extra structure, and in the small, as algebraic structures that generalize groups, monoids, preorders, and graphs. This division manifests in Catlab as well. Large categories (in spirit, if not in the technical sense) occur throughout Catlab as @instances of the theory of categories. For computational reasons, small categories are usually presented by generators and relations.\n\nThis module provides a minimal interface to accomodate both situations. Category instances are supported through the wrapper type TypeCat. Finitely presented categories are provided by another module, FinCats.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.Cat","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.Cat","text":"Alias for Category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.CatSize","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.CatSize","text":"Size of a category, used for dispatch and subtyping purposes.\n\nA Category type having a particular CatSize means that categories of that type are at most that large.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.Category","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.Category","text":"Abstract base type for a category.\n\nThe objects and morphisms in the category have Julia types Ob and Hom, respectively. Note that these types do not necessarily form an @instance of the theory of categories, as they may not meaningfully form a category outside the context of this object. For example, a finite category regarded as a reflexive graph with a composition operation might have type Cat{Int,Int}, where the objects and morphisms are numerical identifiers for vertices and edges in the graph.\n\nThe basic operations available in any category are: dom, codom, id, compose.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.CompositeFunctor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.CompositeFunctor","text":"Composite of functors.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.Functor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.Functor","text":"Abstract base type for a functor between categories.\n\nA functor has a domain and a codomain (dom and codom), which are categories, and object and morphism maps, which can be evaluated using ob_map and hom_map. The functor object can also be called directly when the objects and morphisms have distinct Julia types. This is sometimes but not always the case (see Category), so when writing generic code one should prefer the ob_map and hom_map functions.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.FunctorCallable","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.FunctorCallable","text":"Functor defined by two Julia callables, an object map and a morphism map.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.IdentityFunctor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.IdentityFunctor","text":"Identity functor on a category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.LargeCatSize","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.LargeCatSize","text":"Size of a large category, such as Set.\n\nTo the extent that they form a category, we regard Julia types and functions (TypeCat) as forming a large category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.OppositeCat","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.OppositeCat","text":"Opposite category, where morphism are reversed.\n\nCall op(::Cat) instead of directly instantiating this type.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.OppositeFunctor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.OppositeFunctor","text":"Opposite functor, given by the same mapping between opposite categories.\n\nCall op(::Functor) instead of directly instantiating this type.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.Transformation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.Transformation","text":"Abstract base type for a natural transformation between functors.\n\nA natural transformation α F G has a domain F and codomain G (dom and codom), which are functors FG C D having the same domain C and codomain D. The transformation consists of a component αₓ Fx Gx in D for each object x C, accessible using component or indexing notation (Base.getindex).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.TypeCat","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.TypeCat","text":"Pair of Julia types regarded as a category.\n\nThe Julia types should form an @instance of the theory of categories (Theories.Category).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.codom-Tuple{Category, Any}","page":"Categorical algebra","title":"AlgebraicInterfaces.codom","text":"Codomain of morphism in category.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.compose-Tuple{Category, Vararg{Any}}","page":"Categorical algebra","title":"AlgebraicInterfaces.compose","text":"Compose morphisms in a category.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.dom-Tuple{Category, Any}","page":"Categorical algebra","title":"AlgebraicInterfaces.dom","text":"Domain of morphism in category.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.hom","page":"Categorical algebra","title":"AlgebraicInterfaces.hom","text":"Coerce or look up morphism in category.\n\nSee also: ob.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.id-Tuple{Category, Any}","page":"Categorical algebra","title":"AlgebraicInterfaces.id","text":"Identity morphism on object in category.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#AlgebraicInterfaces.ob","page":"Categorical algebra","title":"AlgebraicInterfaces.ob","text":"Coerce or look up object in category.\n\nConverts the input to an object in the category, which should be of type Ob in a category of type Cat{Ob,Hom}. How this works depends on the category, but a common case is to look up objects, which might be integers or GAT expressions, by their human-readable name, usually a symbol.\n\nSee also: hom.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.co","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.co","text":"2-cell dual of a 2-category.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.codom_ob-Tuple{Transformation}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.codom_ob","text":"Codomain object of natural transformation.\n\nGiven α F G C D, this function returns D.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.component","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.component","text":"Component of natural transformation.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.dom_ob-Tuple{Transformation}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.dom_ob","text":"Domain object of natural transformation.\n\nGiven α F G C D, this function returns C.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.hom_map-Tuple{Functor, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.hom_map","text":"Evaluate functor on morphism.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.is_hom_equal-Tuple{Category, Any, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.is_hom_equal","text":"Are two morphisms in a category equal?\n\nBy default, just checks for equality of Julia objects using ==. In some categories, checking equality of morphisms may involve nontrivial reasoning.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Categories.ob_map-Tuple{Functor, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Categories.ob_map","text":"Evaluate functor on object.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#GATlab.Stdlib.StdModels.op-Tuple{Category}","page":"Categorical algebra","title":"GATlab.Stdlib.StdModels.op","text":"Oppositization 2-functor.\n\nThe oppositization endo-2-functor on Cat, sending a category to its opposite, is covariant on objects and morphisms and contravariant on 2-morphisms, i.e., is a 2-functor op Catᶜᵒ Cat. For more explanation, see the nLab.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats","text":"2-category of finitely presented categories.\n\nThis module is for the 2-category Cat what the module FinSets is for the category Set: a finitary, combinatorial setting where explicit calculations can be carried out. We emphasize that the prefix Fin means \"finitely presented,\" not \"finite,\" as finite categories are too restrictive a notion for many purposes. For example, the free category on a graph is finite if and only if the graph is DAG, which is a fairly special condition. This usage of Fin is also consistent with FinSet because for sets, being finite and being finitely presented are equivalent.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinCat","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinCat","text":"A finitely presented (but not necessarily finite!) category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinCatGraph","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinCatGraph","text":"Abstract type for category backed by finite generating graph.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinCatGraphEq","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinCatGraphEq","text":"Category presented by a finite graph together with path equations.\n\nThe objects of the category are vertices in the graph and the morphisms are paths, quotiented by the congruence relation generated by the path equations. See (Spivak, 2014, Category theory for the sciences, §4.5).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinCatPathGraph","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinCatPathGraph","text":"Abstract type for category whose morphisms are paths in a graph.\n\n(Or equivalence classes of paths in a graph, but we compute with\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinCatPresentation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinCatPresentation","text":"Category defined by a Presentation object.\n\nThe presentation type can, of course, be a category (Theories.Category). It can also be a schema (Theories.Schema). In this case, the schema's objects and attribute types are regarded as the category's objects and the schema's morphisms, attributes, and attribute types as the category's morphisms (where the attribute types are identity morphisms). When the schema is formalized as a profunctor whose codomain category is discrete, this amounts to taking the collage of the profunctor.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinCatSize","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinCatSize","text":"Size of a finitely presented category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinDomFunctor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinDomFunctor","text":"A functor out of a finitely presented category.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinDomFunctorMap","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinDomFunctorMap","text":"Functor out of a finitely presented category given by explicit mappings.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinFunctor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinFunctor","text":"A functor between finitely presented categories.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinTransformation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinTransformation","text":"A natural transformation whose domain category is finitely generated.\n\nThis type is for natural transformations α F G C D such that the domain category C is finitely generated. Such a natural transformation is given by a finite amount of data (one morphism in D for each generating object of C) and its naturality is verified by finitely many equations (one equation for each generating morphism of C).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FinTransformationMap","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FinTransformationMap","text":"Natural transformation with components given by explicit mapping.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.FreeCatGraph","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.FreeCatGraph","text":"Free category generated by a finite graph.\n\nThe objects of the free category are vertices in the graph and the morphisms are (possibly empty) paths.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.Path","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.Path","text":"Path in a graph.\n\nThe path is allowed to be empty but always has definite start and end points (source and target vertices).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.collect_hom-Tuple{Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.collect_hom","text":"Collect assignments of functor's morphism map as a vector.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.collect_ob-Tuple{Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.collect_ob","text":"Collect assignments of functor's object map as a vector.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.components-Tuple{Transformation{C, D, Dom, Codom} where {C<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}), D<:Category, Dom<:(Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})), Codom<:(Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}))}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.components","text":"Components of a natural transformation.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.dom_to_graph-Union{Tuple{Functor{Dom, <:Category{Ob, Hom}}}, Tuple{Hom}, Tuple{Ob}, Tuple{Dom}, Tuple{Functor{Dom, <:Category{Ob, Hom}}, Any}, Tuple{Functor{Dom, <:Category{Ob, Hom}}, Any, Any}} where {Dom, Ob, Hom}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.dom_to_graph","text":"Reinterpret a functor on a finitely presented category as a functor on the equivalent category (ignoring equations) free on a graph. Also normalizes the input to have vector obmap and hommap, with valtype optionally specified. This is useful when the domain is empty or when the maps might be tightly typed but need to allow for types such as that of identity morphisms upon mutation.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.force","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.force","text":"Force evaluation of lazily defined function or functor. The resulting obmap and hommap are guaranteed to have valtype or eltype, as appropriate, equal to Ob and Hom, respectively. \n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.functoriality_failures-Tuple{Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.functoriality_failures","text":"Failures of the purported functor on a presented category to be functorial.\n\nSimilar to is_functorial (and with the same caveats) but returns iterators of functoriality failures: one for domain incompatibilities, one for codomain incompatibilities, and one for equations that are not satisfied.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.graph-Tuple{Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.graph","text":"Graph underlying a finitely presented category whose object and hom generators are indexable, other than one explicitly generated by a graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.graph-Tuple{FinCatGraph}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.graph","text":"Generating graph for a finitely presented category.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.hom_generator","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.hom_generator","text":"Coerce or look up morphism generator in a finitely presented category.\n\nSince morphism generators often have a different data type than morphisms (e.g., in a free category on a graph, the morphism generators are edges and the morphisms are paths), the return type of this function is generally different than that of hom.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.hom_generator_name","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.hom_generator_name","text":"Name of morphism generator, if any.\n\nWhen morphism generators have names, this function is a one-sided inverse to hom_generator. See also: ob_generator_name.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.hom_generators","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.hom_generators","text":"Morphism generators of finitely presented category.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.is_discrete-Tuple{Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.is_discrete","text":"Is the category discrete?\n\nA category is discrete if it is has no non-identity morphisms.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.is_free-Tuple{Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.is_free","text":"Is the category freely generated?\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.is_functorial-Tuple{Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.is_functorial","text":"Is the purported functor on a presented category functorial?\n\nThis function checks that functor preserves domains and codomains. When check_equations is true (the default is false), it also purports to check that the functor preserves all equations in the domain category. No nontrivial checks are currently implemented, so this only functions for identity functors.\n\nSee also: `functoriality_failures' and is_natural.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.is_initial-Tuple{Functor{Dom, Codom} where {Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}), Codom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.is_initial","text":"Dual to a final functor, an initial functor is one for which pulling back diagrams along it does not change the limits of these diagrams.\n\nThis amounts to checking, for a functor C->D, that, for every object d in Ob(D), the comma category (F/d) is connected.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.is_natural-Tuple{Transformation{C, D, Dom, Codom} where {C<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}), D<:Category, Dom<:(Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})), Codom<:(Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}))}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.is_natural","text":"Is the transformation between FinDomFunctors a natural transformation?\n\nThis function uses the fact that to check whether a transformation is natural, it suffices to check the naturality equations on a generating set of morphisms of the domain category. In some cases, checking the equations may be expensive or impossible. When the keyword argument check_equations is false, only the domains and codomains of the components are checked.\n\nSee also: is_functorial.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.make_map-Union{Tuple{T}, Tuple{Any, UnitRange{Int64}, Type{T}}} where T","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.make_map","text":"Maps f over a UnitRange to produce a Vector, or else over anything to produce a Dict. The type paramter functions to ensure the return type is as desired even when the input is empty.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.mappairs-Union{Tuple{T}, Tuple{V}, Tuple{K}, Tuple{Any, Any, T}} where {K, V, T<:AbstractDict{K, V}}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.mappairs","text":"Map two given functions across the respective keys and values of a dictionary.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.mapvals-Union{Tuple{T}, Tuple{Any, T}} where T<:AbstractDict","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.mapvals","text":"Map a function, which may depend on the key, across the values of a dictionary.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.ob_generator","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.ob_generator","text":"Coerce or look up object generator in a finitely presented category.\n\nBecause object generators usually coincide with objects, the default method for ob in finitely presented categories simply calls this function.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.ob_generator_name","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.ob_generator_name","text":"Name of object generator, if any.\n\nWhen object generators have names, this function is a one-sided inverse to ob_generator in that ob_generator(C, ob_generator_name(C, x)) == x.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.ob_generators","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.ob_generators","text":"Object generators of finitely presented category.\n\nThe object generators of finite presented category are almost always the same as the objects. In principle, however, it is possible to have equations between objects, so that there are fewer objects than object generators.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.presentation-Tuple{Catlab.CategoricalAlgebra.FinCats.FinCatPresentation}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.presentation","text":"Computes the graph generating a finitely presented category. Ignores any attribute side and any equations. Optionally returns the mappings from generators to their indices in the resulting graph.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Acsets","page":"Categorical algebra","title":"Acsets","text":"","category":"section"},{"location":"apis/categorical_algebra/#Overview-and-Theory","page":"Categorical algebra","title":"Overview and Theory","text":"","category":"section"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"For an in depth look into the theory behind acsets, we refer the reader to our paper on the subject, which also gives some sense as to how the implementation works. Here, we give a brief tutorial before the the API documentation.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The most essential part of the acset machinery is the schema. The schema parameterizes the acset: each schema corresponds to a different type of acset. Schemas consist of four parts.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Objects XY ((X,Y,Z)::Ob)\nHomomorphisms f colon X to Y (f :: Hom(X,Y)), which go from objects to objects\nAttribute types mathttT (T :: AttrType)\nAttributes a colon X to mathttT (a :: Attr(X,T)), which go from objects to data types","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"For those with a categorical background, a schema is a presentation of a category S along with a functor S from S to the arrow category 0 to 1, such that S^-1(1) is discrete.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"An acset F on a schema consists of...","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"a set F(X) of \"primary keys\" for each object\na function F(f) colon F(X) to F(Y) for each morphism\na Julia data type F(mathttT) for each data type mathttT\na function F(a) colon F(X) to F(mathttT) for each attribute a.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"For those with a categorical background, an acset on a schema S consists of a functor from S to mathsfSet, such that objects in S^-1(0) map to finite sets, and objects in S^-1(1) map to sets that represent types. For any particular functor K colon S^-1(1) to mathsfSet, we can also take the category of acsets that restrict to this map on S^-1.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"We can also add equations to this presentation, but we currently do nothing with those equations in the implementation; they mostly serve as documentation.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"We will now give an example of how this all works in practice.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"using GATlab, Catlab.CategoricalAlgebra\n\n# Write down the schema for a weighted graph\n@present SchWeightedGraph(FreeSchema) begin\n V::Ob\n E::Ob\n src::Hom(E,V)\n tgt::Hom(E,V)\n T::AttrType\n weight::Attr(E,T)\nend\n\n# Construct the type used to store acsets on the previous schema\n# We *index* src and tgt, which means that we store not only\n# the forwards map, but also the backwards map.\n@acset_type WeightedGraph(SchWeightedGraph, index=[:src,:tgt])\n\n# Construct a weighted graph, with floats as edge weights\ng = @acset WeightedGraph{Float64} begin\n V = 4\n E = 5\n src = [1,1,1,2,3]\n tgt = [2,3,4,4,4]\n weight = [7.2, 9.3, 9.4, 0.1, 42.0]\nend","category":"page"},{"location":"apis/categorical_algebra/#API","page":"Categorical algebra","title":"API","text":"","category":"section"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The mathematical abstraction of an acset can of course be implemented in many different ways. Currently, there are three implementations of acsets in Catlab, which share a great deal of code.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"These implementations can be split into two categories.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The first category is static acset types. In this implementation, different schemas correspond to different Julia types. Methods on these Julia types are then custom-generated for the schema, using CompTime.jl.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Under this category, there are two classes of static acset types. The first class is acset types that are generated using the @acset_type macro. These acset types are custom-derived structs. The advantage of this is that the structs have names like Graph or WiringDiagram that are printed out in error messages. The disadvantage is that if you are taking in schemas at runtime, you have to eval code in order to use them.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Here is an example of using @acset_type","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"@acset_type WeightedGraph(SchWeightedGraph, index=[:src,:tgt])\ng = WeightedGraph()","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The second class is AnonACSets. Like acset types derived from @acset_type, these contain the schema in their type. However, they also contain the type of their fields in their types, so the types printed out in error messages are long and ugly. The advantage of these is that they can be used in situations where the schema is passed in at runtime, and they don't require using eval to create a new acset type.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Here is an example of using AnonACSet","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"const WeightedGraph = AnonACSetType(SchWeightedGraph, index=[:src,:tgt])\ng = WeightedGraph()","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"The second category is dynamic acset types. Currently, there is just one type that falls under this category: DynamicACSet. This type has a field for the schema, and no code-generation is done for operations on acsets of this type. This means that if the schema is large compared to the data, this type will often be faster than the static acsets.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"However, dynamics acsets are a new addition to Catlab, and much of the machinery of limits, colimits, and other high-level acset constructions assumes that the schema of an acset can be derived from the type. Thus, more work will have to be done before dynamic acsets become a drop-in replacement for static acsets.","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Here is an example of using a dynamic acset","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"g = DynamicACSet(\"WeightedGraph\", SchWeightedGraph; index=[:src,:tgt])","category":"page"},{"location":"apis/categorical_algebra/","page":"Categorical algebra","title":"Categorical algebra","text":"Modules = [\n CategoricalAlgebra.CSets,\n CategoricalAlgebra.FunctorialDataMigrations,\n CategoricalAlgebra.Chase,\n CategoricalAlgebra.StructuredCospans,\n]\nPrivate = false","category":"page"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets","text":"Categories of C-sets and attributed C-sets.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.ACSetMorphism","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.ACSetMorphism","text":"Common type for ACSetTransformation and CSetTransformation.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.ACSetTransformation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.ACSetTransformation","text":"Transformation between attributed C-sets.\n\nHomomorphisms of attributed C-sets generalize homomorphisms of C-sets (CSetTransformation), which you should understand before reading this.\n\nA homomorphism of attributed C-sets with schema S: C ↛ A (a profunctor) is a natural transformation between the corresponding functors col(S) → Set, where col(S) is the collage of S. When the components on attribute types, indexed by objects of A, are all identity functions, the morphism is called tight; in general, it is called loose. With this terminology, acsets on a fixed schema are the objects of an ℳ-category (see Catlab.Theories.MCategory). Calling ACSetTransformation will construct a tight or loose morphism as appropriate, depending on which components are specified.\n\nSince every tight morphism can be considered a loose one, the distinction between tight and loose may seem a minor technicality, but it has important consequences because limits and colimits in a category depend as much on the morphisms as on the objects. In particular, limits and colimits of acsets differ greatly depending on whether they are taken in the category of acsets with tight morphisms or with loose morphisms. Tight morphisms suffice for many purposes, including most applications of colimits. However, when computing limits of acsets, loose morphisms are usually preferable. For more information about limits and colimits in these categories, see TightACSetTransformation and LooseACSetTransformation.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.ACSetTransformation-Tuple{ACSet, ACSet}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.ACSetTransformation","text":"Move components as first argument\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.ACSetTransformation-Tuple{StructACSet}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.ACSetTransformation","text":"A map f (from A to B) as a map from A to a subobject of B\n\ni.e. get the image of f as a subobject of B\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.ACSetTransformation-Tuple{Subobject{<:StructACSet{S}} where S}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.ACSetTransformation","text":"A map f (from A to B) as a map of subobjects of A to subjects of B\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.CSetTransformation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.CSetTransformation","text":"Transformation between C-sets.\n\nRecall that a C-set homomorphism is a natural transformation: a transformation between functors C → Set satisfying the naturality axiom for every morphism, or equivalently every generating morphism, in C.\n\nThis data type records the data of a C-set transformation. Naturality is not strictly enforced but is expected to be satisfied. It can be checked using the function is_natural.\n\nIf the schema of the dom and codom has attributes, this has the semantics of being a valid C-set transformation on the combinatorial data alone (including attribute variables, if any).\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.LooseACSetTransformation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.LooseACSetTransformation","text":"Loose transformation between attributed C-sets.\n\nLimits and colimits in the category of attributed C-sets and loose homomorphisms are computed pointwise on both objects and attribute types. This implies that (co)limits of Julia types must be computed. Due to limitations in the expressivity of Julia's type system, only certain simple kinds of (co)limits, such as products, are supported.\n\nAlternatively, colimits involving loose acset transformations can be constructed with respect to explicitly given attribute type components for the legs of the cocone, via the keyword argument type_components to colimit and related functions. This uses the universal property of the colimit. To see how this works, notice that a diagram of acsets and loose acset transformations can be expressed as a diagram D: J → C-Set (for the C-sets) along with another diagram A: J → C-Set (for the attribute sets) and a natural transformation α: D ⇒ A (assigning attributes). Given a natural transformation τ: A ⇒ ΔB to a constant functor ΔB, with components given by type_components, the composite transformation α⋅τ: D ⇒ ΔB is a cocone under D, hence factors through the colimit cocone of D. This factoring yields an assigment of attributes to the colimit in C-Set.\n\nFor the distinction between tight and loose, see ACSetTranformation.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.SubCSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.SubCSet","text":"Sub-C-set of a C-set.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.TightACSetTransformation","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.TightACSetTransformation","text":"Tight transformation between attributed C-sets.\n\nThe category of attributed C-sets and tight homomorphisms is isomorphic to a slice category of C-Set, as explained in our paper \"Categorical Data Structures for Technical Computing\". Colimits in this category thus reduce to colimits of C-sets, by a standard result about slice categories. Limits are more complicated and are currently not supported.\n\nFor the distinction between tight and loose, see ACSetTranformation.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#ACSets.ACSetInterface.copy_parts!-Tuple{ACSet, Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})}","page":"Categorical algebra","title":"ACSets.ACSetInterface.copy_parts!","text":"Copy parts from a set-valued FinDomFunctor to an ACSet.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.abstract_attributes","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.abstract_attributes","text":"For any ACSet, X, a canonical map A→X where A has distinct variables for all attributes valued in attrtypes present in abstract (by default: all attrtypes)\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.in_bounds-Tuple{ACSetTransformation}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.in_bounds","text":"Check whether an ACSetTransformation is still valid, despite possible deletion of elements in the codomain. An ACSetTransformation that isn't in bounds will throw an error, rather than return false, if run through is_natural.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.is_cartesian","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.is_cartesian","text":"is_cartesian(f,hs)\n\nChecks if an acset transformation f is cartesian at the homs in the list hs. Expects the homs to be given as a list of Symbols.\n\n\n\n\n\n","category":"function"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.naturality_failures-Tuple{Any, Any, Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.naturality_failures","text":"Returns a dictionary whose keys are contained in the names in arrows(S) and whose value at :f, for an arrow (f,c,d), is a lazy iterator over the elements of X(c) on which α's naturality square for f does not commute. Components should be a NamedTuple or Dictionary with keys contained in the names of S's morphisms and values vectors or dicts defining partial functions from X(c) to Y(c).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.CSets.show_naturality_failures-Tuple{IO, AbstractDict}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.CSets.show_naturality_failures","text":"Pretty-print failures of transformation to be natural.\n\nSee also: naturality_failures.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FinCats.is_natural-Tuple{LooseACSetTransformation}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FinCats.is_natural","text":"Check naturality condition for a purported ACSetTransformation, α: X→Y. For each hom in the schema, e.g. h: m → n, the following square must commute:\n\n αₘ\n Xₘ --> Yₘ\nXₕ ↓ ✓ ↓ Yₕ\n Xₙ --> Yₙ\n αₙ\n\nYou're allowed to run this on a named tuple partly specifying an ACSetTransformation, though at this time the domain and codomain must be fully specified ACSets.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations","text":"Functorial data migration for attributed C-sets.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.DataMigrationFunctor","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.DataMigrationFunctor","text":"Data migration functor given contravariantly. Stores a contravariant migration.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.internal_hom-Union{Tuple{T}, Tuple{T, T}} where T<:ACSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.internal_hom","text":"Objects: Fᴳ(c) = C-Set(C × G, F) where C is the representable c\n\nGiven a map f: a->b, we compute that f(Aᵢ) = Bⱼ by constructing the following: Aᵢ A × G → F f*↑ ↑ ↑ ↗ Bⱼ find the hom Bⱼ that makes this commute B × G \n\nwhere f* is given by yoneda.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.migrate!-Tuple{ACSet, ACSet, Catlab.CategoricalAlgebra.FunctorialDataMigrations.AbstractDataMigration}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.migrate!","text":"Contravariantly migrate data from the acset Y to the acset X.\n\nThis is the mutating variant of migrate!. When the functor on schemas is the identity, this operation is equivalent to copy_parts!.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.migrate-Tuple{Functor{Dom} where Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}), Catlab.CategoricalAlgebra.FunctorialDataMigrations.ContravariantMigration{F} where F<:(Functor{Dom, Codom} where {Dom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom}), Codom<:(Category{Ob, Hom, Catlab.CategoricalAlgebra.FinCats.FinCatSize} where {Ob, Hom})})}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.migrate","text":"Apply a Δ migration by simple precomposition.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.migrate-Union{Tuple{T}, Tuple{Type{T}, ACSet, Catlab.CategoricalAlgebra.FunctorialDataMigrations.AbstractDataMigration}} where T<:ACSet","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.migrate","text":"Contravariantly migrate data from the acset Y to a new acset of type T.\n\nThe mutating variant of this function is migrate!.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.representable-Tuple{Any, Symbol}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.representable","text":"Construct a representable C-set.\n\nRecall that a representable C-set is one of form C(c-) C Set for some object c C.\n\nThis function computes the c representable as the left pushforward data migration of the singleton c-set along the inclusion functor c C, which works because left Kan extensions take representables to representables (Mac Lane 1978, Exercise X.3.2). Besides the intrinsic difficulties with representables (they can be infinite), this function thus inherits any limitations of our implementation of left pushforward data migrations.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.subobject_classifier-Tuple{Type}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.subobject_classifier","text":"The subobject classifier Ω in a presheaf topos is the presheaf that sends each object A to the set of sieves on it (equivalently, the set of subobjects of the representable presheaf for A). Counting subobjects gives us the number of A parts; the hom data for f:A->B for subobject Aᵢ is determined via:\n\nAᵢ ↪ A ↑ ↑ f* PB⌝↪ B (PB picks out a subobject of B, up to isomorphism.)\n\n(where A and B are the representables for objects A and B and f* is the unique map from B into the A which sends the point of B to f applied to the point of A)\n\nReturns the classifier as well as a dictionary of subobjects corresponding to the parts of the classifier.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.FunctorialDataMigrations.yoneda-Tuple{Any}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.FunctorialDataMigrations.yoneda","text":"Compute the Yoneda embedding of a category C in the category of C-sets.\n\nBecause Catlab privileges copresheaves (C-sets) over presheaves, this is the contravariant Yoneda embedding, i.e., the embedding functor C^op → C-Set.\n\nThe first argument cons is a constructor for the ACSet, such as a struct acset type. If representables have already been computed (which can be expensive), they can be supplied via the cache keyword argument.\n\nReturns a FinDomFunctor with domain op(C).\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#GATlab.Models.SymbolicModels.functor-Tuple{DataMigrationFunctor}","page":"Categorical algebra","title":"GATlab.Models.SymbolicModels.functor","text":"Gives the underlying schema functor of a data migration seen as a functor of acset categories.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Chase","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Chase","text":"The chase is an algorithm which subjects a C-Set instance to constraints expressed in the language of regular logic, called embedded dependencies (EDs, or 'triggers'). \n\nA morphism S->T, encodes an embedded dependency. If the pattern S is matched (via a homomorphism S->I), we demand there exist a morphism T->I (for some database instance I) that makes the triangle commute in order to satisfy the dependency (if this is not the case, then the trigger is 'active').\n\nHomomorphisms can merge elements and introduce new ones. The former kind are called \"equality generating dependencies\" (EGDs) and the latter \"tuple generating dependencies\" (TGDs). Any homomorphism can be factored into EGD and TGD components by, respectively, restricting the codomain to the image or restricting the domain to the coimage.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.Chase.chase-Tuple{ACSet, AbstractDict, Int64}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.Chase.chase","text":"chase(I::ACSet, Σ::AbstractDict, n::Int)\n\nChase a C-Set or C-Rel instance given a list of embedded dependencies. This may not terminate, so a bound n on the number of iterations is required.\n\n[,]\n\nΣS ⟶ Iₙ ⊕↓ ⋮ (resulting morphism) ΣT ... Iₙ₊₁\n\nThere is a copy of S and T for each active trigger. A trigger is a map from S into the current instance. What makes it 'active' is that there is no morphism from T to I that makes the triangle commute.\n\nEach iteration constructs the above pushout square. The result is a morphism, so that one can keep track of the provenance of elements in the original CSet instance within the chased result.\n\nWhether or not the result is due to success or timeout is returned as a boolean flag.\n\nTODO: this algorithm could be made more efficient by homomorphism caching.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans","text":"Structured cospans.\n\nThis module provides a generic interface for structured cospans with a concrete implementation for attributed C-sets.\n\n\n\n\n\n","category":"module"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.OpenACSetLeg","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.OpenACSetLeg","text":"Leg of a structured (multi)cospan of acsets in R-form.\n\nA convenience type that contains the data of an acset transformation, except for the codomain, since that data is already given by the decoration of the R-form structured cospan.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan","text":"Structured cospan.\n\nThe first type parameter L encodes a functor L: A → X from the base category A, often FinSet, to a category X with \"extra structure.\" An L-structured cospan is then a cospan in X whose feet are images under L of objects in A. The category X is assumed to have pushouts.\n\nStructured cospans form a double category with no further assumptions on the functor L. To obtain a symmetric monoidal double category, L must preserve finite coproducts. In practice, L usually has a right adjoint R: X → A, which implies that L preserves all finite colimits. It also allows structured cospans to be constructed more conveniently from an object x in X plus a cospan in A with apex R(x).\n\nSee also: StructuredMulticospan.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan-Union{Tuple{L}, Tuple{Any, Multicospan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}} where L","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan","text":"Construct structured cospan in R-form.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan-Union{Tuple{L}, Tuple{Multicospan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, StaticArraysCore.StaticArray{Tuple{2}, T, 1} where T}} where L","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan","text":"Construct structured cospan in L-form.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanOb","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanOb","text":"Object in the category of L-structured cospans.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.StructuredMulticospan","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.StructuredMulticospan","text":"Structured multicospan.\n\nA structured multicospan is like a structured cospan except that it may have a number of legs different than two.\n\nSee also: StructuredCospan.\n\n\n\n\n\n","category":"type"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.StructuredMulticospan-Union{Tuple{L}, Tuple{Any, Multicospan}} where L","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.StructuredMulticospan","text":"Construct structured multicospan in R-form.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.OpenACSetTypes-Union{Tuple{X}, Tuple{S}, Tuple{Type{X}, Symbol}} where {S, X<:(StructACSet{S})}","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.OpenACSetTypes","text":"Create types for open attributed C-sets from an attributed C-set type.\n\nThe type parameters of the given acset type should not be instantiated with specific Julia types. This function returns a pair of types, one for objects, a subtype of StructuredCospanOb, and one for morphisms, a subtype of StructuredMulticospan. Both types will have the same type parameters for attribute types as the given acset type.\n\nMathematically speaking, this function sets up structured (multi)cospans with a functor L A X between categories of acsets that creates \"discrete acsets.\" Such a \"discrete acset functor\" is a functor that is left adjoint to a certain kind of forgetful functor between categories of acsets, namely one that is a pullback along an inclusion of schemas such that the image of inclusion has no outgoing arrows. For example, the schema inclusion V E V has this property but E E V does not.\n\nSee also: OpenCSetTypes.\n\n\n\n\n\n","category":"method"},{"location":"apis/categorical_algebra/#Catlab.CategoricalAlgebra.StructuredCospans.OpenCSetTypes-Union{Tuple{X}, Tuple{Type{X}, Vararg{Any}}} where X<:(StructCSet)","page":"Categorical algebra","title":"Catlab.CategoricalAlgebra.StructuredCospans.OpenCSetTypes","text":"Create types for open C-sets from a C-set type.\n\nA special case of OpenACSetTypes. See there for details.\n\n\n\n\n\n","category":"method"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"EditURL = \"../../../literate/sketches/preorders.jl\"","category":"page"},{"location":"generated/sketches/preorders/#Preorders","page":"Preorders","title":"Preorders","text":"","category":"section"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"(Image: )","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Many of the ideas in category theory can be viewed as generalizations of preorders or monoids. This sketch shows some features of Catlab through the lens of preorders. You will see examples of defining GATs, Presentations, Syntax, and Functors. These are illustrated with preorders or thin categories, which are particularly simple cases of categories.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"using Core: GeneratedFunctionStub\nusing Test\n\nusing Catlab.Theories, Catlab.CategoricalAlgebra\nimport Catlab.Theories: compose","category":"page"},{"location":"generated/sketches/preorders/#Definition-of-a-Preorder-formalized-as-a-GAT","page":"Preorders","title":"Definition of a Preorder formalized as a GAT","text":"","category":"section"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"The following definitions can be found in the Catlab.Theories module.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"\"\"\" Theory of *preorders*\n\nPreorders encode the axioms of reflexivity and transitivity as term constructors.\n\"\"\"\n@theory Preorder{El,Leq} begin\n El::TYPE\n Leq(lhs::El, rhs::El)::TYPE\n @op (≤) := Leq\n\n # Preorder axioms are lifted to term constructors in the GAT.\n reflexive(A::El)::(A≤A) # ∀ A there is a term reflexive(A) which implies A≤A\n transitive(f::(A≤B), g::(B≤C))::(A≤C) ⊣ (A::El, B::El, C::El)\n\n # Axioms of the GAT are equivalences on terms or simplification rules in the logic\n f == g ⊣ (A::El, B::El, f::(A≤B), g::(A≤B))\n # Read as (f⟹ A≤B ∧ g⟹ A≤B) ⟹ f ≡ g\nend","category":"page"},{"location":"generated/sketches/preorders/#Preorders-are-Thin-Categories","page":"Preorders","title":"Preorders are Thin Categories","text":"","category":"section"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Definition of a thin category","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@theory ThinCategory{Ob,Hom} <: Category{Ob,Hom} begin\n f == g ⊣ (A::Ob, B::Ob, f::Hom(A,B), g::Hom(A,B))\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"of course this definition extends the GAT of categories","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@theory Category{Ob,Hom} begin\n # Unicode aliases.\n @op begin\n (→) := Hom\n (⋅) := compose\n end\n\n \"\"\" Object in a category \"\"\"\n Ob::TYPE\n\n \"\"\" Morphism in a category \"\"\"\n Hom(dom::Ob,codom::Ob)::TYPE\n\n id(A::Ob)::(A → A)\n compose(f::(A → B), g::(B → C))::(A → C) ⊣ (A::Ob, B::Ob, C::Ob)\n\n # Category axioms.\n ((f ⋅ g) ⋅ h == f ⋅ (g ⋅ h)\n ⊣ (A::Ob, B::Ob, C::Ob, D::Ob, f::(A → B), g::(B → C), h::(C → D)))\n f ⋅ id(B) == f ⊣ (A::Ob, B::Ob, f::(A → B))\n id(A) ⋅ f == f ⊣ (A::Ob, B::Ob, f::(A → B))\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Exercise: construct an isomorphism between the theory of thin categories and the theory of preorders. Show that they have the same models.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Once you have a GAT defined using the @theory macro, you can define presentations, which are logical syntax for giving examples of the theory. The GAT contains type and term constructors that you can use to write expressions. A presentation uses those expressions to create a specific example of the theory. We define P to be a preorder with 3 elements and 2 ≤ relationships.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@present P(FreeThinCategory) begin\n (X,Y,Z)::Ob\n f::Hom(X,Y)\n g::Hom(Y,Z)\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"another example","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@present Q(FreeThinCategory) begin\n (X,Y,Z)::Ob\n f::Hom(X,Y)\n g::Hom(Y,Z)\n Y′::Ob\n f′::Hom(X,Y′)\n g′::Hom(Y′,Z)\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Exercise: draw the Hasse diagrams for these preorders by hand.","category":"page"},{"location":"generated/sketches/preorders/#Composition-is-transitivity","page":"Preorders","title":"Composition is transitivity","text":"","category":"section"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"expressions in the presentation are paths in the Hasse Diagram","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"function compose(P::Presentation, vs::Vector{Symbol})\n compose(collect(generator(P, v) for v in vs))\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"expressions are represented at expression trees","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"ex = compose(P, [:f, :g])","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"the head of an expression is the root of the expression tree","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"head(ex)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"the julia type of the expression","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"typeof(ex)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"the GAT type of the expression","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"gat_typeof(ex)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"the parameters of the GAT Type","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"gat_type_args(ex)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"in any thin category there is at most one morphism between any pair of objects. In symbols: ex₁::Hom(X,Y) ∧ ex₂::Hom(X,Y) ⟹ ex₁ == ex₂","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"function thinequal(ex₁::FreeThinCategory.Hom, ex₂::FreeThinCategory.Hom)\n dom(ex₁) == dom(ex₂) && codom(ex₁) == codom(ex₂)\nend\n\n@test thinequal(ex, compose(P, [:f,:g])⋅id(generator(P,:Z)))","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Thinking in terms of preorders, the composite f⋅g::Hom(X,Z) is a proof that X ≤ Z in logical notation you would say f::Hom(X,Y) and g::Hom(Y,Z) ⊢ f⋅g::Hom(X,Z) given a proof that X≤Y and a proof of Y≤Z then ⋅ will create a proof of X≤Z by composing the proofs sequentially like chaining inequalities in math a key aspect of category theory is that you want to work constructively you don't want to know that there exists a composite, you want to hold onto that composite. in programming, the way that you hold onto things is putting data into data structures. While computers can access things by offset or addresses, programmers want to use names so when we prove in P that X≤Z, we name that proof by adding it as a generator","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@present P₂(FreeThinCategory) begin\n (X,Y,Z)::Ob\n f::Hom(X,Y)\n g::Hom(Y,Z)\n h::Hom(X,Z)\nend\n\nex = compose(P₂, [:f, :g])","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Now that we have a name for h, we can see that thinequal knows that f⋅g == h because according to the definition of a thin category, any two morphisms with the same domain and codomain are equal.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@test thinequal(ex, generator(P₂, :h))","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"There is an imperative interface to manipulating presentations by mutating them for this purpose","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"P₂′ = copy(P)\nadd_generator!(P₂′, Hom(:h, P[:X], P[:Z]))\ngenerators(P₂′)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"We could avoid this naming the homs situation by giving all the homs the same name however, then when you tried to write down a morphism, you wouldn't be able to refer to a specific one by name, because they are all named ≤.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@present R(FreeThinCategory) begin\n (x,y,z)::Ob\n (≤)::Hom(x,y)\nend\ngenerators(R)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Catlab won't let you make a presentation where the homs have the same exact name. So, this will error:","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@present Q(FreeThinCategory) begin\n (x,y,z)::Ob\n (≤)::Hom(x,y)\n (≤)::Hom(y,z)\n (≤)::Hom(x,z)\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"However, you can omit the names for homs with the following syntax, which is useful for thin categories.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"@present Q(FreeThinCategory) begin\n (x,y,z)::Ob\n ::Hom(x,y)\n ::Hom(y,z)\n ::Hom(x,z)\nend","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"In a thin category, all the homs with the same domain and codomain are the same, so why don't we name them by their the domain and codomain and then use the property that any two homs with the same name are the same to encode the thinness. This is what the Hasse diagram representation does for us. The edges in the diagram are encoding the presentation data into a combinatorial object that we can visualize. There are many reasons to encode a logical structure into a combinatorial strucuture, one is that we generally have ways of drawing combinatorial objects that convey their saliant structure and enable visual reasoning. Another is algorithms, isomorphism between the combinatorial representations provide some of the isomorphisms between the logical structures. in this case, a graph homomorphism between Hasse Diagrams construct isomorphisms between the preorders they present. The converse is not true since there can be many Graphs that present the same preorder.","category":"page"},{"location":"generated/sketches/preorders/#Monotone-Maps","page":"Preorders","title":"Monotone Maps","text":"","category":"section"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"a generator is in the set of homs if it is in the list of generators","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"in_homs(f::FreeThinCategory.Hom{:generator}, C::FinCat) =\n f in hom_generators(C)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"a composite hom is in the list set of homs if all of its components are.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"in_homs(f::FreeThinCategory.Hom{:compose}, C::FinCat) =\n all(fᵢ->in_homs(fᵢ, C), args(f))","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"we can check if a map is functorial, which is called monotone for preorders.","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"make sure all the objects in the domain are sent to objects in the codomain\nmake sure all the homs are sent to homs in the codomain\ncheck that the domains and codomainss of the homs match","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"function is_functorial(F::FinFunctor)\n pₒ = map(ob_generators(dom(F))) do X\n F(X) in ob_generators(codom(F))\n end |> all\n\n pₕ = map(hom_generators(dom(F))) do f\n in_homs(F(f), codom(F))\n end |> all\n\n pᵩ = map(hom_generators(dom(F))) do f\n FX = F(dom(f))\n FY = F(codom(f))\n Ff = F(f)\n dom(Ff) == FX && codom(Ff) == FY\n end |> all\n return pₒ && pₕ && pᵩ\nend\n\n@present Q(FreeThinCategory) begin\n (a,b,c,d)::Ob\n ab::Hom(a,b)\n bc::Hom(b,c)\n cd::Hom(c,d)\nend\ngenerators(Q)\n\nFₒ = Dict(:X=>:a, :Y=>:b, :Z=>:c)\nFₕ = Dict(:f=>:ab, :g=>:bc)\nF = FinFunctor(Fₒ, Fₕ, P, Q)\n@test is_functorial(F)\n\nFₒ = Dict(:X=>:a, :Y=>:b, :Z=>:d)\nFₕ = Dict(:f=>:ab, :g=>[:bc, :cd])\nF = FinFunctor(Fₒ, Fₕ, P, Q)\n@test is_functorial(F)\n\n\nFₒ = Dict(:X=>:a, :Y=>:b, :Z=>:c)\nFₕ = Dict(:f=>:ab, :g=>[:bc, :cd])\nF = FinFunctor(Fₒ, Fₕ, P, Q)\n@test !is_functorial(F)","category":"page"},{"location":"generated/sketches/preorders/","page":"Preorders","title":"Preorders","text":"Monotone maps are functors for thin categories. One of the benefits of category theory is that we find abstractions that work in multiple domains. The abstraction of preserving the domains and codomains of morphisms is a key abstraction that we can use to define many notions in mathematics.","category":"page"},{"location":"apis/wiring_diagrams/#wiring_diagrams","page":"Wiring diagrams","title":"Wiring diagrams","text":"","category":"section"},{"location":"apis/wiring_diagrams/","page":"Wiring diagrams","title":"Wiring diagrams","text":"Modules = [\n WiringDiagrams.DirectedWiringDiagrams,\n WiringDiagrams.UndirectedWiringDiagrams,\n WiringDiagrams.MonoidalDirectedWiringDiagrams,\n WiringDiagrams.WiringDiagramAlgorithms,\n WiringDiagrams.WiringDiagramSerialization,\n WiringDiagrams.GraphMLWiringDiagrams,\n WiringDiagrams.JSONWiringDiagrams,\n]\nPrivate = false","category":"page"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams","text":"Data structure for (directed) wiring diagrams, aka string diagrams.\n\nA (directed) wiring diagram consists of a collection of boxes with input and output ports connected by wires. A box can be atomic (possessing no internal structure) or can itself be a wiring diagram. Thus, wiring diagrams can be nested recursively. Wiring diagrams are closely related to what the CS literature calls \"directed graphs with ports\" or more simply \"port graphs\". The main difference is that a wiring diagram has an \"outer box\": a wiring diagram has its own ports that can be connected to the ports of its boxes.\n\nThis module provides a generic data structure for wiring diagrams. Arbitrary data can be attached to the boxes, ports, and wires of a wiring diagram. The diagrams are \"abstract\" in the sense that they cannot be directly rendered as raster or vector graphics. However, they form a useful intermediate representation that can be serialized to and from GraphML or translated into Graphviz or other declarative diagram languages.\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.AbstractBox","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.AbstractBox","text":"Base type for any box (node) in a wiring diagram.\n\nThis type represents an arbitrary black box with inputs and outputs.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.Box","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.Box","text":"An atomic box in a wiring diagram.\n\nThese boxes have no internal structure.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.Port","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.Port","text":"A port on a box to which wires can be connected.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.PortKind","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.PortKind","text":"Kind of port: input or output.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.Wire","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.Wire","text":"A wire connecting one port to another.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.CategoricalAlgebra.FinCats.graph-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.CategoricalAlgebra.FinCats.graph","text":"Grapn underlying wiring diagram, including parts for noin-internal wires.\n\nThe graph has two special vertices representing the input and output boundaries of the outer box.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.encapsulate-Tuple{WiringDiagram, Vector{Int64}}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.encapsulate","text":"Encapsulate multiple boxes within a single sub-diagram.\n\nThis operation is a (one-sided) inverse to subsitution, see substitute.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.encapsulated_subdiagram-Union{Tuple{WD}, Tuple{WD, Vector{Int64}}} where WD<:WiringDiagram","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.encapsulated_subdiagram","text":"Create an encapsulating box for a set of boxes in a wiring diagram.\n\nTo a first approximation, the union of input ports of the given boxes will become the inputs ports of the encapsulating box and likewise for the output ports. However, when copies or merges occur, as in a cartesian or cocartesian category, a simplification procedure may reduce the number of ports on the encapsulating box.\n\nSpecifically:\n\nEach input port of an encapsulated box will have at most one incoming wire\n\nfrom the encapsulating outer box, and each output port of an encapsulated box will have at most one outgoing wire to the encapsulating outer box.\n\nA set of ports connected to the same outside (non-encapsulated) ports will be\n\nsimplified into a single port of the encapsulating box.\n\nSee also induced_subdiagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.in_wires-Tuple{WiringDiagram, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.in_wires","text":"Get all wires coming into the box.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.in_wires-Tuple{WiringDiagram, Port}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.in_wires","text":"Get all wires coming into the port.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.induced_subdiagram-Union{Tuple{T}, Tuple{WiringDiagram{T}, Vector{Int64}}} where T","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.induced_subdiagram","text":"The wiring diagram induced by a subset of its boxes.\n\nSee also encapsulated_subdiagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.internal_graph-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.internal_graph","text":"Graph underlying wiring diagram, with edges for internal wires only.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.ocompose-Tuple{WiringDiagram, Vector{<:WiringDiagram}}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.ocompose","text":"Operadic composition of wiring diagrams.\n\nThis generic function has two different signatures, corresponding to the \"full\" and \"partial\" notions of operadic composition (Yau, 2018, Operads of Wiring Diagrams, Definitions 2.3 and 2.10).\n\nThis operation is a simple wrapper around substitute.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.out_wires-Tuple{WiringDiagram, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.out_wires","text":"Get all wires coming out of the box.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.out_wires-Tuple{WiringDiagram, Port}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.out_wires","text":"Get all wires coming out of the port.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.singleton_diagram-Tuple{Type, AbstractBox}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.singleton_diagram","text":"Wiring diagram with a single box connected to the outer ports.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.substitute-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.substitute","text":"Substitute wiring diagrams for boxes.\n\nPerforms one or more substitutions. When performing multiple substitutions, the substitutions are simultaneous.\n\nThis operation implements the operadic composition of wiring diagrams, see also ocompose.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.validate_ports-Tuple{Any, Any}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.validate_ports","text":"Check compatibility of source and target ports.\n\nThe default implementation is a no-op.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.wires-Tuple{WiringDiagram, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.wires","text":"Get all wires coming into or out of the box.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams","text":"Data structure for undirected wiring diagrams.\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.AbstractUWD","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.AbstractUWD","text":"Abstract type for UWDs, typed or untyped, possibly with extra attributes.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.HasUWD","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.HasUWD","text":"Abstract type for C-sets that contain a UWD.\n\nThis type includes UWDs, scheduled UWDs, and nested UWDs.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.TypedUWD","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.TypedUWD","text":"A typed undirected wiring diagram.\n\nA UWD whose ports and junctions must be compatibly typed.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.UntypedUWD","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.UntypedUWD","text":"An undirected wiring diagram.\n\nThe most basic kind of UWD, without types or other extra attributes.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.DirectedWiringDiagrams.add_wire!-Tuple{AbstractUWD, Tuple{Int64, Int64}, Tuple{Int64, Int64}}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.DirectedWiringDiagrams.add_wire!","text":"Wire together two ports in an undirected wiring diagram.\n\nA convenience method that creates and sets junctions as needed. Ports are only allowed to have one junction, so if both ports already have junctions, then the second port is assigned the junction of the first. The handling of the two arguments is otherwise symmetric.\n\nFIXME: When both ports already have junctions, the two junctions should be merged. To do this, we must implement merge_junctions! and thus also rem_part!.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.cospan_diagram-Union{Tuple{UWD}, Tuple{Type{UWD}, SetFunction{Dom, Codom} where {Dom<:(FinSet{Int64}), Codom<:(FinSet{Int64})}, SetFunction{Dom, Codom} where {Dom<:(FinSet{Int64}), Codom<:(FinSet{Int64})}}, Tuple{Type{UWD}, SetFunction{Dom, Codom} where {Dom<:(FinSet{Int64}), Codom<:(FinSet{Int64})}, SetFunction{Dom, Codom} where {Dom<:(FinSet{Int64}), Codom<:(FinSet{Int64})}, Any}} where UWD<:AbstractUWD","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.cospan_diagram","text":"Undirected wiring diagram defined by a cospan.\n\nThe wiring diagram has a single box. The ports of this box, the outer ports, the junctions, and the connections between them are defined by the cospan. Thus, this function generalizes singleton_diagram.\n\nSee also: junction_diagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.junction_diagram-Union{Tuple{UWD}, Tuple{Type{UWD}, SetFunction{Dom, Codom} where {Dom<:(FinSet{Int64}), Codom<:(FinSet{Int64})}}, Tuple{Type{UWD}, SetFunction{Dom, Codom} where {Dom<:(FinSet{Int64}), Codom<:(FinSet{Int64})}, Any}} where UWD<:AbstractUWD","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.junction_diagram","text":"Undirected wiring diagram with no boxes, only junctions.\n\nSee also: singleton_diagram, cospan_diagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams","text":"Wiring diagrams as a symmetric monoidal category.\n\nThis module provides a high-level categorical interface to wiring diagrams, building on the low-level imperative interface and the operadic interface. It also defines data types and functions to represent diagonals, codiagonals, duals, caps, cups, daggers, and other gadgets in wiring diagrams.\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.BoxOp","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.BoxOp","text":"Box wrapping another box.\n\nRepresents unary operations on boxes in wiring diagrams.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.Junction","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.Junction","text":"Junction node in a wiring diagram.\n\nJunction nodes are used to explicitly represent copies, merges, deletions, creations, caps, and cups.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.PortOp","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.PortOp","text":"Port value wrapping another value.\n\nRepresents unary operations on ports in wiring diagrams.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.Ports","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.Ports","text":"A list of ports.\n\nThe objects in categories of wiring diagrams.\n\n\n\n\n\n","category":"type"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.add_junctions-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.add_junctions","text":"Add junction nodes to wiring diagram.\n\nTransforms from the implicit to the explicit representation of diagonals and codiagonals. This operation is inverse to rem_junctions.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.implicit_mcopy-Tuple{Ports, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.implicit_mcopy","text":"Implicit copy in wiring diagram.\n\nCopies are represented by multiple outgoing wires from a single port and deletions by no outgoing wires.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.implicit_mmerge-Tuple{Ports, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.implicit_mmerge","text":"Implicit merge in wiring diagram.\n\nMerges are represented by multiple incoming wires into a single port and creations by no incoming wires.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junction_caps-Tuple{Ports}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junction_caps","text":"Wiring diagram of nested caps made out of junction nodes.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junction_cups-Tuple{Ports}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junction_cups","text":"Wiring diagram of nested cups made out of junction nodes.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junctioned_mcopy-Tuple{Ports, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junctioned_mcopy","text":"Explicit copy in wiring diagram.\n\nCopies and deletions are represented by junctions (boxes of type Junction).\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junctioned_mmerge-Tuple{Ports, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.junctioned_mmerge","text":"Explicit merge in wiring diagram.\n\nMerges and creations are represented by junctions (boxes of type Junction).\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.merge_junctions-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.merge_junctions","text":"Merge adjacent junction nodes into single junctions.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.rem_junctions-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.MonoidalDirectedWiringDiagrams.rem_junctions","text":"Remove junction nodes from wiring diagram.\n\nTransforms from the explicit to the implicit representation of diagonals and codiagonals. This operation is inverse to add_junctions.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.UndirectedWiringDiagrams.junction_diagram-Tuple{Ports, Int64, Int64}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.UndirectedWiringDiagrams.junction_diagram","text":"Wiring diagram with a junction node for each of the given ports.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#GATlab.Models.SymbolicModels.functor-Tuple{WiringDiagram, Any, Any}","page":"Wiring diagrams","title":"GATlab.Models.SymbolicModels.functor","text":"Apply functor in a category of wiring diagrams.\n\nDefined by compatible mappings of ports and boxes.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.WiringDiagramAlgorithms","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.WiringDiagramAlgorithms","text":"Algorithms on wiring diagrams.\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.Graphs.GraphAlgorithms.topological_sort-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.Graphs.GraphAlgorithms.topological_sort","text":"Topological sort of boxes in wiring diagram.\n\nReturns a list of box IDs, excluding the outer box's input and output IDs.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.WiringDiagramAlgorithms.crossing_minimization_by_sort-Tuple{WiringDiagram, AbstractVector}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.WiringDiagramAlgorithms.crossing_minimization_by_sort","text":"Crossing minimization by sorting a univariate statistic.\n\nThe boxes in sources and/or targets are fixed and the boxes in vs are permuted. A permutation σ of the latter is returned, such that vs[σ] are the sorted box IDs. Both one-sided and two-sided crossing minimization are supported, depending on whether just one, or both, of sources and targets are given.\n\nIn this simple but popular heuristic algorithm, the boxes are permuted by sorting a univariate statistic of the positions of incoming and/or outgoing wires. Typical choices are:\n\nmean: the sample mean, yielding the \"barycenter method\"\nmedian: the sample median\n\nIn both cases, this algorithm has the property that if there is a permutation with no crossings, it will find it.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_cartesian!-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_cartesian!","text":"Put a wiring diagram for a cartesian category into normal form.\n\nThis function puts a wiring diagram representing a morphism in a free cartesian category into normal form. Copies and deletions are simplified as much as possible.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_copy!-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_copy!","text":"Normalize copies in a wiring diagram.\n\nThis function maximizes sharing of intermediate computations in a wiring diagram where copies are natural.\n\nThis algorithm is basically the same as the congruence closure algorithm on term graphs, in the special case of the empty relation R = ∅ (Baader & Nipkow, 1998, Term Rewriting and All That, Sec. 4.4). The main difference is the possibility of zero or many function outputs.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_delete!-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.WiringDiagramAlgorithms.normalize_delete!","text":"Normalize deletions in a wiring diagram.\n\nThis function removes all unused intermediate computations in a wiring diagram where deletion is natural.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.WiringDiagramSerialization","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.WiringDiagramSerialization","text":"Conventions for serialization of wiring diagrams.\n\nDefines a consistent set of names for boxes, ports, and wires to be used when serializing wiring diagrams, as well as conventions for serializing box, port, and wire attributes.\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.GraphMLWiringDiagrams","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.GraphMLWiringDiagrams","text":"Serialize abstract wiring diagrams as GraphML.\n\nSerialization of box, port, and wire values can be overloaded by data type (see convert_to_graphml_data and convert_from_graphml_data).\n\nGraphML is the closest thing to a de jure and de facto standard in the space of graph data formats, supported by a variety of graph applications and libraries. We depart mildly from the GraphML spec by allowing JSON data attributes for GraphML nodes, ports, and edges.\n\nReferences:\n\nGraphML Primer: http://graphml.graphdrawing.org/primer/graphml-primer.html\nGraphML DTD: http://graphml.graphdrawing.org/specification/dtd.html\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.GraphMLWiringDiagrams.generate_graphml-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.GraphMLWiringDiagrams.generate_graphml","text":"Generate GraphML representing a wiring diagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.GraphMLWiringDiagrams.parse_graphml-Tuple{Type, Type, Type, AbstractString}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.GraphMLWiringDiagrams.parse_graphml","text":"Parse a wiring diagram from a GraphML string or XML document.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.GraphMLWiringDiagrams.read_graphml-Tuple{Type, Type, Type, String}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.GraphMLWiringDiagrams.read_graphml","text":"Read a wiring diagram from a GraphML file.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.GraphMLWiringDiagrams.write_graphml-Tuple{WiringDiagram, String}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.GraphMLWiringDiagrams.write_graphml","text":"Write a wiring diagram to a file as GraphML.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.JSONWiringDiagrams","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.JSONWiringDiagrams","text":"Serialize abstract wiring diagrams as JSON.\n\nJSON data formats are convenient when programming for the web. Unfortunately, no standard for JSON graph formats has gained any kind of widespread adoption. We adopt a format compatible with that used by the KEILER project and its successor ELK (Eclipse Layout Kernel). This format is roughly feature compatible with GraphML, supporting nested graphs and ports. It also supports layout information like node position and size.\n\nReferences:\n\nKEILER's JSON graph format: https://rtsys.informatik.uni-kiel.de/confluence/display/KIELER/JSON+Graph+Format\nELK's JSON graph format: https://www.eclipse.org/elk/documentation/tooldevelopers/graphdatastructure/jsonformat.html\n\n\n\n\n\n","category":"module"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.JSONWiringDiagrams.generate_json_graph-Tuple{WiringDiagram}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.JSONWiringDiagrams.generate_json_graph","text":"Generate a JSON dict representing a wiring diagram.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.JSONWiringDiagrams.parse_json_graph-Tuple{Type, Type, Type, Union{AbstractString, IO}}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.JSONWiringDiagrams.parse_json_graph","text":"Parse a wiring diagram from a JSON string or dict.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.JSONWiringDiagrams.read_json_graph-Tuple{Type, Type, Type, String}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.JSONWiringDiagrams.read_json_graph","text":"Read a wiring diagram from a JSON file.\n\n\n\n\n\n","category":"method"},{"location":"apis/wiring_diagrams/#Catlab.WiringDiagrams.JSONWiringDiagrams.write_json_graph-Tuple{WiringDiagram, String}","page":"Wiring diagrams","title":"Catlab.WiringDiagrams.JSONWiringDiagrams.write_json_graph","text":"Write a wiring diagram to a file as JSON.\n\n\n\n\n\n","category":"method"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"EditURL = \"../../../literate/graphics/graphviz_graphs.jl\"","category":"page"},{"location":"generated/graphics/graphviz_graphs/#Drawing-graphs-in-Graphviz","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"","category":"section"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"(Image: )","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"All of the basic graph types provided by the Catlab Graphs module can be drawn using Graphviz. By default, \"directed\" graph types (Graph, ReflexiveGraph) are drawn using the dot program and \"undirected\" graph types (SymmetricGraph, HalfEdgeGraph) are drawn using the neato program.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"using Catlab.Graphs, Catlab.Graphics","category":"page"},{"location":"generated/graphics/graphviz_graphs/#Drawing-basic-graphs","page":"Drawing graphs in Graphviz","title":"Drawing basic graphs","text":"","category":"section"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"g = cycle_graph(Graph, 3)\nto_graphviz(g)","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"sg = cycle_graph(SymmetricGraph, 3)\nto_graphviz(sg)","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"Node and edge IDs can be shown by setting node_labels=true and edge_labels=true, or a data attribute can be used as a label by setting node_labels=:my_vertex_attr and edge_lables=:my_edge_attr.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(g, node_labels=true, edge_labels=true)","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"Graph-level, node-level, and edge-level Graphviz attributes can be supplied using the graph_attrs, node_attrs, and edge_attrs keyword arguments.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(g, node_attrs=Dict(:color => \"cornflowerblue\"),\n edge_attrs=Dict(:style => \"dotted\"))","category":"page"},{"location":"generated/graphics/graphviz_graphs/#Drawing-graph-homomorphisms","page":"Drawing graphs in Graphviz","title":"Drawing graph homomorphisms","text":"","category":"section"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"Graph homomorphsims (ACSetTransformations between graphs) can also be drawn using Graphviz, in several different styles.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"using Catlab.CategoricalAlgebra\n\nf = homomorphism(cycle_graph(Graph, 4), complete_graph(Graph, 2))","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"By default, the domain and codomain graph are both drawn, as well the vertex mapping between them.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(f)","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"To see the edge mapping, which is not necessarily unique in the presence of the multiple edges, colors can be used.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(f, edge_colors=true)","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"Alternatively, the graph homomorphism can be depicted by drawing only the domain graph and coloring its nodes and edges. By default, setting draw_codom=false sets both node_colors=true and edge_colors=true.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(f, draw_codom=false)","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(f, draw_codom=false, edge_colors=false)","category":"page"},{"location":"generated/graphics/graphviz_graphs/#Drawing-maps-between-finite-sets","page":"Drawing graphs in Graphviz","title":"Drawing maps between finite sets","text":"","category":"section"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"It is also possible to visualize maps between finite sets (FinFunctions between FinSets) using Graphviz.","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"using Catlab.CategoricalAlgebra.FinSets\n\nA = FinSet(4)\nB = FinSet(3)\nf = FinFunction([1,3,2,2], A, B)\n\nto_graphviz(f, graph_attrs=Dict(:splines=>\"false\"))","category":"page"},{"location":"generated/graphics/graphviz_graphs/","page":"Drawing graphs in Graphviz","title":"Drawing graphs in Graphviz","text":"to_graphviz(f, node_labels=true,\n graph_attrs=Dict(:splines=>\"false\", :rankdir => \"TB\"))","category":"page"},{"location":"#Catlab.jl","page":"Catlab.jl","title":"Catlab.jl","text":"","category":"section"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Catlab.jl is a framework for applied and computational category theory, written in the Julia language. Catlab provides a programming library and interactive interface for applications of category theory to scientific and engineering fields. It emphasizes monoidal categories due to their wide applicability but can support any categorical structure that is formalizable as a generalized algebraic theory.","category":"page"},{"location":"#What-is-Catlab?","page":"Catlab.jl","title":"What is Catlab?","text":"","category":"section"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Catlab is, or will eventually be, the following things.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Programming library: First and foremost, Catlab provides data structures, algorithms, and serialization for applied category theory. Macros offer a convenient syntax for specifying categorical doctrines and type-safe symbolic manipulation systems. Wiring diagrams (aka string diagrams) are supported through specialized data structures and can be serialized to and from GraphML (an XML-based format) and JSON.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Interactive computing environment: Catlab can also be used interactively in Jupyter notebooks. Symbolic expressions are displayed using LaTeX and wiring diagrams are visualized using Compose.jl, Graphviz, or TikZ.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Computer algebra system: Catlab will serve as a computer algebra system for categorical algebra. Unlike most computer algebra systems, all expressions are typed using fragment of dependent type theory called generalized algebraic theories. We will implement core algorithms for solving word problems and reducing expressions to normal form with respect to several important doctrines, such as those of categories and of symmetric monoidal categories. For the computer algebra of classical abstract algebra, see AbstractAlgebra.jl and Nemo.jl.","category":"page"},{"location":"#What-is-Catlab-not?","page":"Catlab.jl","title":"What is Catlab not?","text":"","category":"section"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Catlab is not currently any of the following things, although we do not rule out that it could eventually evolve in these directions.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Automated theorem prover: Although there is some overlap between computer algebra and automated theorem proving, Catlab cannot be considered a theorem prover because it does not produce formal certificates of correctness (aka proofs).","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Proof assistant: Likewise, Catlab is not a proof assistant because it does not produce formally verifiable proofs. Formal verification is not within scope of the project.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Graphical user interface: Catlab does not provide a wiring diagram editor or other graphical user interface. It is primarily a programming library, not a user-facing application. However, there is another project in the AlgebraicJulia ecosystem, Semagrams.jl which does provide graphical user interfaces for interacting with wiring diagrams, Petri nets, and the like.","category":"page"},{"location":"#What-is-a-GAT?","page":"Catlab.jl","title":"What is a GAT?","text":"","category":"section"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"See GATlab documentation","category":"page"},{"location":"#Conventions","page":"Catlab.jl","title":"Conventions","text":"","category":"section"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"In several places in Catlab, we use what we call \"Abstract Field Convention\". Instead of doing the following:","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"struct Pair{A}\n x1::A\n x2::A\nend\n\nadd(xs::Pair) = xs.x1 + xs.x2\n\nconst IntPair = Pair{Int}","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"which leads to potentially longer and longer type names as the type parameters increase in size, we do","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"\"\"\"\nAbstract Fields\n- x1::A\n- x2::A\n\"\"\"\nabstract type Pair{A} end\n\nadd(xs::Pair) = xs.x1 + xs.x2\n\nstruct IntPair <: Pair{Int}\n x1::Int\n x2::Int\nend","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"That is, we assume that all subtypes of a certain abstract types have the same field names, and are organized in roughly the same way. There is no way of enforcing this within Julia, so instead we leave a comment on the abstract type to document that we are working this way.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Note that this is contrary to the standard wisdom in Julia that one should as much as possible access structs through methods, not field accesses. The reason why we do not do this here is twofold. First of all, sometimes it can be annoying to write out the trivial field-access methods in addition to defining the struct. For instance, we have 12 different structs in src/acsets/ColumnImplementations.jl that all are subtypes of an Abstract Field Convention abstract type. It would be 24 lines of boilerplate to write out the field accessors for these types with little appreciable benefit. The second reason is that the Abstract Field Convention is a stronger guarantee than an interface: we are claiming that any subtype has precisely these fields in this order, and no others! This is essential for defining methods like copy, which might be defined as follows.","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"function copy(p::T) where {T<:Pair}\n T(p.x1, p.x2)\nend","category":"page"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"So the Abstract Field Convention is stronger than a normal interface. It's not really about encapsulating data, it's more about cutting down on long names in debug messages.","category":"page"},{"location":"#Table-of-Contents","page":"Catlab.jl","title":"Table of Contents","text":"","category":"section"},{"location":"","page":"Catlab.jl","title":"Catlab.jl","text":"Pages = [\n \"apis/theories.md\",\n \"apis/wiring_diagrams.md\",\n \"apis/graphics.md\",\n \"apis/programs.md\",\n \"devdocs/style.md\",\n ]\nDepth = 2","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"EditURL = \"../../../literate/sketches/smc.jl\"","category":"page"},{"location":"generated/sketches/smc/#Symmetric-Monoidal-Categories","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"","category":"section"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"(Image: )","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"This vignette supports section 4.4.3 of Seven Sketches in Compositionality, which introduces the definition of symmetric monoidal categories (SMCs). SMCs are a core concept in applied category theory and are a workhorse of Catlab's utility in computing applications. We will discuss the definition as a GAT, see examples of working with formulas, and conversions to wiring diagrams (sometimes called string diagrams). SMCs are useful for modeling mathematical structures like programs or processes where the objects represent data or things and the morphisms represent processes that happen to those things.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"using GATlab, Catlab.Theories\nusing Catlab.CategoricalAlgebra\nusing Catlab.WiringDiagrams\nusing Catlab.Programs\nusing Catlab.Graphics\nusing Catlab.Graphics: Graphviz\n\ndraw(d::WiringDiagram) = to_graphviz(d,\n orientation=LeftToRight,\n labels=true, label_attr=:xlabel,\n node_attrs=Graphviz.Attributes(\n :fontname => \"Courier\",\n ),\n edge_attrs=Graphviz.Attributes(\n :fontname => \"Courier\",\n )\n)","category":"page"},{"location":"generated/sketches/smc/#Definition","page":"Symmetric Monoidal Categories","title":"Definition","text":"","category":"section"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Let 𝒞 be a category, then a strict symmetric monoidal structure on 𝒞 has as data:","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"An object I called the monoidal unit\nA functor ⊗: 𝒞×𝒞 → 𝒞 called the monoidal product.\nA natural isomorphism σᵃᵇ: A⊗B → B⊗A","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"It has as axioms:","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Left identity) I⊗C = C for all objects C in 𝒞\nRight identity) C⊗I = C for all objects C in 𝒞\nAssociativity) (A⊗B)⊗C = A⊗(B⊗C) for all objects A,B,C in 𝒞\nInvolutivity) σ(σ(A,B)) = id(A⊗B)","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"In a category, you have a composition operation that captures the sequential kind of composition. For example in Set, you compose two functions f⋅g by first applying f and then applying g. In monoidal categories, you also have the parallel composition ⊗ which you can think of as representing the simultaneous exectution of two processes. We are familiar with the cartesian product in Set which takes two sets and forms the cartesian product. The cartesian product acts on functions in a similar way, f×g is the function that takes a tuple (x:dom(f),y:dom(g)) and applies them in parallel and returns (f(x), g(y)):(codom(f)×codom(g)). The axioms of an SMC require that these two operations work together. The Seven Sketches book suppresses an interesting axiom called the interchange law for brevity, but it is worth calling some attention to it. In order for the sequential and parallel composition operators to capture our intuition, we need to assert that for any functions with compatible domains we can interchange parallel and sequential operators. Formally, ((f ⊗ g) ⋅ (h ⊗ k) == (f ⋅ h) ⊗ (g ⋅ k) where (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob, f::(A → B), h::(B → C), g::(X → Y), k::(Y → Z))). This axiom says that doing f and g in parallel and then h and k in parallel is the same as doing (f then h) and (g then k) in parallel. When using SMCs to model processes, this axiom is critical to making sure that scheduling those processes is coherent.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"If the SMC is not strict, then the equations are replaced by natural isomorphisms. The choice of natural isomorphisms then becomes part of the data of the SMC. With MacLane's coherence theorem for SMCs mathematicians can think about strict SMCs and not really worry too much about the natural isomorphisms. As programmers, those chickens come home to roost and implementing an SMC requires making some choices about about how to do that strictification.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The Catlab definitions of SMC are repeated here for convenience. Catlab allows you to implement mathematical definitions in the language of Generalized Algebraic Theories (GATs), which are a good fit for the kind of natural language definitions that mathematicians will write. Because Catlab does relatively little type inference, the GAT version of a definition can be more verbose than you would get in natural language. For example, we have to be careful about spelling out the object for an identity morphism id(A):A → A. The notation @theory MonoidalCategory{Ob,Hom} <: Category{Ob,Hom} says that a Monoidal Category is a type of Category with additional components and axioms. Catlab has only rudimentary support for Monoidal Categories that are not Symmetric Monoidal Categories. But we separate out the definitions for completeness.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"@theory MonoidalCategory{Ob,Hom} <: Category{Ob,Hom} begin\n otimes(A::Ob, B::Ob)::Ob\n otimes(f::(A → B), g::(C → D))::((A ⊗ C) → (B ⊗ D)) ⊣\n (A::Ob, B::Ob, C::Ob, D::Ob)\n @op (⊗) := otimes\n munit()::Ob\n # Monoid axioms.\n #\n # The last two axioms are the naturality equations associated with the left\n # and right unitors, in the strict case where they are identities.\n (A ⊗ B) ⊗ C == A ⊗ (B ⊗ C) ⊣ (A::Ob, B::Ob, C::Ob)\n munit() ⊗ A == A ⊣ (A::Ob)\n A ⊗ munit() == A ⊣ (A::Ob)\n (f ⊗ g) ⊗ h == f ⊗ (g ⊗ h) ⊣ (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob,\n f::(A → X), g::(B → Y), h::(C → Z))\n id(munit()) ⊗ f == f ⊣ (A::Ob, B::Ob, f::(A → B))\n f ⊗ id(munit()) == f ⊣ (A::Ob, B::Ob, f::(A → B))\n # Functorality axioms.\n ((f ⊗ g) ⋅ (h ⊗ k) == (f ⋅ h) ⊗ (g ⋅ k)\n ⊣ (A::Ob, B::Ob, C::Ob, X::Ob, Y::Ob, Z::Ob,\n f::(A → B), h::(B → C), g::(X → Y), k::(Y → Z)))\n id(A ⊗ B) == id(A) ⊗ id(B) ⊣ (A::Ob, B::Ob)\nend","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"To the definition of a monoidal category, we need to add the symmetry component. Catlab calls the swap morphism a braid, because that is how you visualize it in wiring diagrams, but we stick with the conventional σ unicode name. The macro @op tells Catlab that you want to use a unicode operator as an alias for you term constructor. If you are familiar with type theory, you might be wondering why we write the context after the terms. This is because human brains are pretty good at type inference based on notational convention and we want to mimic the English idiom \"f⋅g, where f:A→B and g:B→C are functions\".","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"@theory SymmetricMonoidalCategory{Ob,Hom} <: MonoidalCategory{Ob,Hom} begin\n braid(A::Ob, B::Ob)::((A ⊗ B) → (B ⊗ A))\n @op (σ) := braid\n # Involutivity axiom.\n σ(A,B) ⋅ σ(B,A) == id(A ⊗ B) ⊣ (A::Ob, B::Ob)\n # Coherence axioms.\n #\n # Note: The last two axioms are deducible from the first two axioms together\n # with the naturality equations for the left/right unitors. We record them for\n # the sake of clarity and uniformity.\n σ(A,B⊗C) == (σ(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ σ(A,C)) ⊣ (A::Ob, B::Ob, C::Ob)\n σ(A⊗B,C) == (id(A) ⊗ σ(B,C)) ⋅ (σ(A,C) ⊗ id(B)) ⊣ (A::Ob, B::Ob, C::Ob)\n σ(A,munit()) == id(A) ⊣ (A::Ob)\n σ(munit(),A) == id(A) ⊣ (A::Ob)\n # Naturality axiom.\n (f ⊗ g) ⋅ σ(B,D) == σ(A,C) ⋅ (g ⊗ f) ⊣ (A::Ob, B::Ob, C::Ob, D::Ob,\n f::(A → B), g::(C → D))\nend","category":"page"},{"location":"generated/sketches/smc/#Presentations","page":"Symmetric Monoidal Categories","title":"Presentations","text":"","category":"section"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Just like how a preorder can be presented with Hasse Diagram or a free category can be presented by a Graph, SMCs can be presented syntactically or combinatorially. We first start with the syntactic presentation using @present.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"@present Cooking(FreeSymmetricMonoidalCategory) begin\n (WholeEgg, RawEgg, Shell, Egg, Pan, Cheese, Scramble)::Ob\n crack::Hom(WholeEgg, RawEgg⊗Shell)\n fry::Hom(RawEgg⊗Pan, Egg⊗Pan)\n scramble::Hom(RawEgg⊗Cheese⊗Pan, Scramble⊗Pan)\nend\ngenerators(Cooking)","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"One interpretation of an SMC is that the objects are resources and the Homs are processes the domain of the Hom is the list of resources that you need to perform the process and the codomain is the list of resources that the process produces. You can think of the SMC presentation as a namespace containing all the terms in the SMC.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The objects and morphisms are accessible by name","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Cooking[:Egg]\nCooking[:fry]","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Then you can make complex terms using the unicode operators","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"((Cooking[:crack]⋅σ(Cooking[:RawEgg], Cooking[:Shell])) ⊗id(Cooking[:Pan])) ⋅ (id(Cooking[:Shell])⊗Cooking[:fry])","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Notice that Catlab will display the expected domain and codomain.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"This is called point-free notation an it is very popular in the functional programming literature where it is used to mean implicit universal quantification over the function arguments. You can think of a morphism like a function that takes an element of each domain object as input and produces an element of each codomain object as output. Not all SMCs have interpretations as functions over sets, but just like groups can be viewed as a generalization of the symmetries of geometric shapes, SMCs can be viewed as a generalization of multivariate functions.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"These presentations are very syntactic objects and expose an API for manipulating expressions.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"for g in generators(Cooking)\n \"$g is a $(gat_typeof(g)) with arguments $(gat_type_args(g))\"\nend","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The gat_typeof function computes the algebraic type of a term by analogy to Base.typeof which computes the Julia type of a value.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"homs = filter(generators(Cooking)) do g\n gat_typeof(g) == :Hom\nend","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"When the term is a Hom, you can get the domain and codomain of the morphism with the dom and codom functions.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"map(homs) do f\n \"$f: $(dom(f)) → $(codom(f))\"\nend","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The terms in a FreeSymmetricMonoidalCategory are trees that you can navigate with head and args. The head of an expression is the term constructor that created it. For SMCs, this can be :generator, :otimes, :compose, :id, or :braid. Then args will give you the list of arguments to the term constructor. For terms of type Object, this will just be the list of objects that went into constructing the object. For example A⊗B⊗C will have as its head :otimes and as the args [A,B,C]. Note that the head is a symbol, but the args are objects. For a term of type Hom, you have the same structure, but for Homs with the head :generator, you get the name of the morphism as a symbol as the first argument.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"We can look at the head and args of object expressions.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"headargs(x) = (head(x),args(x))\nσ(Cooking[:Egg], Cooking[:Pan]) |> headargs","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"And, morphsims","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"headargs(Cooking[:crack]⊗Cooking[:fry])","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The base case is generators","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"headargs(Cooking[:Egg])","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"And, morphisms","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"headargs(Cooking[:crack])","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"For a more complete introspection of the expression trees, you can call dump(ex) which will print a very verbose representation of the entire expression tree.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"In order to compose morphisms sequentially, you have to make sure that the domains match up. In a typical SMC expression this can require padding with the identity morphism and braiding monoidal products into the right order.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"compose(Cooking[:crack]⊗id(Cooking[:Pan]),\n (id(Cooking[:RawEgg])⊗ σ(Cooking[:Shell], Cooking[:Pan])),\n (Cooking[:fry]⊗id(Cooking[:Shell])))","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"At some point, prefix notation is more scalable than infix notation, so you might write this as a LISP programmer would.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"compose(\n otimes(Cooking[:crack],\n id(Cooking[:Pan])),\n otimes(id(Cooking[:RawEgg]),\n σ(Cooking[:Shell], Cooking[:Pan])),\n otimes(Cooking[:fry],\n id(Cooking[:Shell])))","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"You can view this padding as requiring explicit instructions to do noting with all the objects you aren't using. In this example, we have to tell our chef","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Crack the egg and do nothing with the pan.\nDo nothing with the egg and swap the shell with the pan.\nFry the egg and do nothing with the shell.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Obviously, this is a very tedious way to write recipes. You need to have some syntactic sugar for all this padding and swapping.","category":"page"},{"location":"generated/sketches/smc/#The-Program-Macro","page":"Symmetric Monoidal Categories","title":"The Program Macro","text":"","category":"section"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The syntactic API above is useful for manipulating terms in an arbitrary GAT and is the formal language of Catlab for representing and manipulating algebraic structures. However, when we want to work with big expressions in an SMC, the tree structure inherent to formulas is too verbose, and we want to move to a port-graph structure called DirectedWiringDiagrams. This gives us the benefits of combinatorial data structures like graphs with the right expressional power for representing the morphisms in an SMC.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"recipe = @program Cooking (e::WholeEgg, p::Pan) begin\n e′, shell = crack(e)\n return shell, fry(e′, p)\nend\ndraw(recipe)","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"Catlab gives you the tools for drawing wiring diagrams. Visualization of wiring diagrams is the oldest part of Catlab and the original motivation for its development. The @program macro allows you to define wiring diagrams using a syntax that feels like Julia code.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"The input wires are declared as arguments to the program, and the output wires are declared as returns from the function. Variables that are not consumed or by another function or returned by the program are automatically dropped.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"recipe = @program Cooking (e::WholeEgg, p::Pan) begin\n e′, shell = crack(e)\n return fry(e′, p)\nend\ndraw(recipe)","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"You can copy a value by using it more than once. This is visualized as a wire being split into two wires. Square brackets let you assert equality again. For material goods, you might not want to allow this merging and splitting.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"recipe = @program Cooking (e₁::WholeEgg, e₂::WholeEgg, p::Pan) begin\n e, shell = crack(e₁)\n r₁, p₁ = fry(e, p)\n e, shell = crack(e₂)\n r₂, p₂ = fry(e, p)\n return r₁, r₂, [p₁,p₂]\nend\n\ndraw(recipe)","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"You can visualize the copy and delete morphisms explicitly with the add_junctions function. The dots with one wire input and multiple outputs are copying values and dots with no wires out are deletions (discarding values). Not all instances of a SymmetricMonoidalCategory support copy and delete, for example, in manufacturing you can't duplicate a resource, and in chemistry you can't discard species. Catlab would enforce that when you tried to interpret the wiring diagram in a specific SMC.","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"draw(add_junctions(recipe))","category":"page"},{"location":"generated/sketches/smc/","page":"Symmetric Monoidal Categories","title":"Symmetric Monoidal Categories","text":"For more details about working with wiring diagrams in Catlab, you should look at the vignettes under wiring_diagrams which explain how wiring diagrams interact with SMC expressions and the basics of constructing and manipulation wiring diagrams.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"EditURL = \"../../../literate/graphics/composejl_wiring_diagrams.jl\"","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Drawing-wiring-diagrams-in-Compose.jl","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"(Image: )","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"Catlab can draw wiring diagrams using the Julia package Compose.jl.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"For best results, it is recommended to load the packages Convex.j and SCS.jl. When available they are used to optimize the layout of the outer ports.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"using Catlab.WiringDiagrams, Catlab.Graphics\n\nimport Convex, SCS","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Examples","page":"Drawing wiring diagrams in Compose.jl","title":"Examples","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/#Symmetric-monoidal-category","page":"Drawing wiring diagrams in Compose.jl","title":"Symmetric monoidal category","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"using Catlab.Theories\n\nA, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)\nf, g = Hom(:f, A, B), Hom(:g, B, A);\nnothing #hide","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"To start, here are a few very simple examples.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(f)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(f⋅g)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(f⊗g)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"Here is a more complex example, involving generators with compound domains and codomains.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"h, k = Hom(:h, C, D), Hom(:k, D, C)\nm, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)\nq = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)\n\nto_composejl((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"Identities and braidings appear as wires.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(id(A))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(braid(A,B))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"The isomorphism A otimes B otimes C to C otimes B otimes A induced by the permutation (3 2 1) is a composite of braidings and identities.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))\n\nto_composejl(σ)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"By default, anchor points are added along identity and braiding wires to reproduce the expression structure in the layout. The anchors can be disabled to get a more \"unbiased\" layout.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(σ, anchor_wires=false)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Biproduct-category","page":"Drawing wiring diagrams in Compose.jl","title":"Biproduct category","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)\nf = Hom(:f, A, B)\n\nto_composejl(mcopy(A))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(delete(A))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(mcopy(A)⋅(f⊗f)⋅mmerge(B))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(mcopy(A⊗B), orientation=TopToBottom)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(mcopy(A⊗B⊗C), orientation=TopToBottom)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Compact-closed-category","page":"Drawing wiring diagrams in Compose.jl","title":"Compact closed category","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"The unit and co-unit of a compact closed category appear as caps and cups.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"A, B = Ob(FreeCompactClosedCategory, :A, :B)\n\nto_composejl(dunit(A))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(dcounit(A))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"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:","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"A, B = Ob(FreeBicategoryRelations, :A, :B)\nf = Hom(:f, A, B)\n\nto_composejl((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Abelian-bicategory-of-relations","page":"Drawing wiring diagrams in Compose.jl","title":"Abelian bicategory of relations","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"In an abelian bicategory of relations, such as the category of linear 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.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"X = Ob(FreeAbelianBicategoryRelations, :X)\n\nto_composejl(plus(X) ⋅ mcopy(X))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl((mcopy(X)⊕mcopy(X)) ⋅ (id(X)⊕swap(X,X)⊕id(X)) ⋅ (plus(X)⊕plus(X)))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Custom-styles","page":"Drawing wiring diagrams in Compose.jl","title":"Custom styles","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"The visual appearance of wiring diagrams can be customized by passing Compose properties.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"using Compose: fill, stroke\n\nA, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)\nf, g = Hom(:f, A, B), Hom(:g, B, A)\n\nto_composejl(f⋅g, props=Dict(\n :box => [fill(\"lavender\"), stroke(\"black\")],\n))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"X = Ob(FreeAbelianBicategoryRelations, :X)\n\nto_composejl(plus(X) ⋅ mcopy(X), props=Dict(\n :junction => [fill(\"red\"), stroke(\"black\")],\n :variant_junction => [fill(\"blue\"), stroke(\"black\")],\n))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"The background color can also be changed.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(f⋅g, background_color=\"lightgray\", props=Dict(\n :box => [fill(\"white\"), stroke(\"black\")],\n))","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"By default, the boxes are rectangular (:rectangle). Other available shapes include circles (:circle) and ellipses (:ellipse).","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"to_composejl(f⋅g, default_box_shape=:circle)","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/#Output-formats","page":"Drawing wiring diagrams in Compose.jl","title":"Output formats","text":"","category":"section"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"The function to_composejl returns a ComposePicture object, which contains a Compose.jl context as well as a recommended width and height. When displayed interactively, this object is rendered using Compose's SVG backend.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"Any backend can be used by calling Compose's draw function. The SVG and PGF (LaTeX) backends are always available. To use the PNG or PDF backends, the extra packages Cairo.jl and Fontconfig.jl must be installed.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"For example, here is how to use the PGF backend.","category":"page"},{"location":"generated/graphics/composejl_wiring_diagrams/","page":"Drawing wiring diagrams in Compose.jl","title":"Drawing wiring diagrams in Compose.jl","text":"using Compose: draw, PGF\n\npic = to_composejl(f⋅g, rounded_boxes=false)\npgf = sprint() do io\n pgf_backend = PGF(io, pic.width, pic.height,\n false, # emit_on_finish\n true, # only_tikz\n texfonts=true)\n draw(pgf_backend, pic.context)\nend\nprintln(pgf)","category":"page"}] +} diff --git a/v0.16.12/siteinfo.js b/v0.16.12/siteinfo.js new file mode 100644 index 000000000..d7370f884 --- /dev/null +++ b/v0.16.12/siteinfo.js @@ -0,0 +1 @@ +var DOCUMENTER_CURRENT_VERSION = "v0.16.12"; diff --git a/versions.js b/versions.js index 4cf1e627c..3ed38ed85 100644 --- a/versions.js +++ b/versions.js @@ -15,5 +15,5 @@ var DOC_VERSIONS = [ "v0.3", "dev", ]; -var DOCUMENTER_NEWEST = "v0.16.11"; +var DOCUMENTER_NEWEST = "v0.16.12"; var DOCUMENTER_STABLE = "stable";