From 3ac9cfeff2c13465cf8432f6c3f297d9d95b4e81 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Sat, 22 Jun 2024 01:40:29 +0000 Subject: [PATCH] build based on 546453c --- dev/.documenter-siteinfo.json | 2 +- dev/api/index.html | 8 ++++---- dev/generated/full_demo/index.html | 2 +- dev/generated/game_of_life.ipynb | 18 +++++++++--------- dev/generated/game_of_life/index.html | 2 +- dev/generated/lotka_volterra/index.html | 2 +- dev/generated/ptg_simple/index.html | 2 +- dev/index.html | 2 +- dev/objects.inv | Bin 4548 -> 4560 bytes dev/search_index.js | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index bb6943b..3ac1a8a 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-06-18T19:26:02","documenter_version":"1.4.1"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-06-22T01:40:25","documenter_version":"1.4.1"}} \ No newline at end of file diff --git a/dev/api/index.html b/dev/api/index.html index 7ae020d..ed6eb9d 100644 --- a/dev/api/index.html +++ b/dev/api/index.html @@ -1,7 +1,7 @@ -Library Reference · AlgebraicRewriting.jl

Library Reference

Rewrite

AlgebraicRewriting.Rewrite.Constraints.QuantifierType

Quantified edge

e - which edge is filled in kind - Exists, Forall, or Exists! st - "such that", restrict the domain of quantification via a condition monic - restrict domain of quanitification to only monic matches

source
Catlab.Theories.:⊗Method

Combine two constraints conjunctively, sharing as much of the computation graph as possible (i.e. pushout along the maximum common subgraph)

source
AlgebraicRewriting.Rewrite.Utils.RuleType

Rewrite rules which are (usually) encoded as spans. The L structure encodes a pattern to be matched. The R morphism encodes a replacement pattern to be substituted in. They are related to each other by an interface I with maps: L ⟵ I ⟶ R

A semantics (DPO, SPO, CoNeg, or SqPO) must be chosen.

Control the match-finding process by specifying whether the match is intended to be monic or not, as well as an optional application condition(s)

source
AlgebraicRewriting.Rewrite.Utils.get_matchesMethod

Get list of possible matches based on the constraints of the rule

This function has the same behavior as the generic get_matches, but it is more performant because we do not have to query all homomorphisms before finding a valid match, in case n=1.

source
AlgebraicRewriting.Rewrite.Utils.check_match_var_eqsMethod

A match may be invalid because two variables (which are to be assigned different values via the I -> R map) are identified (due to merging via the I->L map, which morally ought be monic but is not for AttrVars). We can check this before computing the pushout to make sure that we will not get an inconsistent result when trying to compute it. This requires executing the custom exprs of the rewrite rule, so we may wish to build in the ability to skip this step if that is computationally intensive.

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
rewrite_match_maps(r::Rule{:DPO}, m)

Apply a DPO rewrite rule (given as a span, L<-I->R) to a ACSet using a match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H

This works for any type that implements pushout_complement and pushout

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
rewrite_match_maps(r::Rule{:CoNeg}, m)

Apply a CoNegation rewrite rule (given as a span, L↩I->R) to a ACSet using a monic match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H where K = ~L ∨ I

This works for any type that implements bi-Heyting logic operators ~ and ∨.

This is described here. Essentially, it is partway between DPO and SPO. Suppose the rule tries to delete two things, one of which satisfies the dangling condition, the other violates it. While DPO would fail to apply at all, and SPO would delete both things (cascading the deletion for the latter), co-negation rewriting would simply delete the item which can be deleted without cascading and ignore the other element.

It includes a quote which indicates that this method should work even when the match morphism isn't monic, if it satisfies the identification condition. Supporting this is not yet implemented.

Match morphisms which bind attribute variables are not monic, hence we this form of rewriting doesn't support VarACSets. Intuitively, it feels like this restriction could be relaxed.

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
rewrite_match_maps(r::Rule{:SqPO},m; pres::Union{Nothing, Presentation}=nothing)

Sesqui-pushout is just like DPO, except we use a final pullback complement instead of a pushout complement.

r.L  r.R

L <-⌞K -> R m ↓ ↓k ↓ r I <- • ->⌜O i o

source
AlgebraicRewriting.Rewrite.PBPO.PBPORuleType
  l    r

L ⟵ K ⟶ R tl ↓ ↓ tk <== tl, tk must be monic L' ⟵ K'

It is assumed we never want the typing/adherence match to be monic, but we can optionally restrict the match L → G to be monic.

We can attach application conditions to both the match morphism as well as the adherence morphism. Until morphism search under constraints becomes efficient, it's sometimes needed to just directly state the adherence morphism as a function of the match morphism.

source
AlgebraicRewriting.Rewrite.PBPO.partial_abstractMethod

This construction addresses the following problem: ideally when we 'abstract' an ACSet from X to A->X, maps into X, say B->X, can be canonically pulled back to maps B->A which commute. However, A won't do here, because there may not even exist any maps B->A. If B has concrete attributes, then those cannot be sent to an AttrVar in A. Furthermore, if B has multiple 'references' to an AttrVar (two different edges, each with AttrVar(1), sent to two different edges with the same atttribute value in X), then there is no longer a canonical place to send AttrVar(1) to in A, as there is a distinct AttrVar for every single part+attr in X. So we need a construction which does two things to A->X, starting with a map B->X. 1.) replaces exactly the variables we need with concrete values in order to allow a map B->A, 2.) quotients variables in A so that there is exactly one choice for where to send attrvars in B such that the triangle commutes.

Starting with a map L -> G (where G has no AttrVars), we want the analogous map into a "partially abstracted" version of G that has concrete attributes replaced with AttrVars EXCEPT for those attributes which are mapped to by concrete attributes of L. Likewise, multiple occurences of the same variable in L correspond to AttrVars which should be merged in the partially-abstracted G.

For example, for a schema with a single Ob and Attr (where all combinatorial maps are just {1↦1, 2↦2}):

  • L = [AttrVar(1), :foo]

  • G = [:bar, :foo, :baz]

  • abs(G) = [AttrVar(1), AttrVar(2), AttrVar(3)]

  • expected result: [AttrVar(1), :foo, AttrVar(2)]

    L -> Partial_abs(G) ↓ ↑ G <- abs(G)

This function computes the top arrow of this diagram starting with the left arrow. The bottom arrow is computed by abstract_attributes and the right arrow by sub_vars. Furthermore, a map from Partial_abs(G) to G is provided.

This is the factorization system arising from a coreflective subcategory.

(see https://ncatlab.org/nlab/show/reflective+factorization+system and https://blog.algebraicjulia.org/post/2023/06/varacsets/)

source
AlgebraicRewriting.Rewrite.Utils.get_matchesMethod

PBPO matches consist of two morphisms. First, a match m: L → G, and secondly a typing G → L′. With attributes, it is not so simple because G has concrete values for attributes and L′ may have variables. Therefore, we actually change the typing to map out of A, an abstracted version of G (with its attributes replaced by variables). So we lift matches L->G to matches L->A, then search α∈Hom(A,L′).

In general, we want α to be uniquely determined by m, so by default α_unique is set to true.

 m

L⌟ ⟶ G || ↓ α L ⟶ L′ tl

 m

L ⟶ G tl ↓ ↘a ↑ (abs = partial abstraction. Note a is Labs in the code.) L′⟵ A α

The "strong match" condition we enforce is that: tl⁻¹(α(A)) = a⁻¹(A). This means we can deduce precisely what m is by looking at α.

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
         r
+Library Reference · AlgebraicRewriting.jl

Library Reference

Rewrite

AlgebraicRewriting.Rewrite.Constraints.QuantifierType

Quantified edge

e - which edge is filled in kind - Exists, Forall, or Exists! st - "such that", restrict the domain of quantification via a condition monic - restrict domain of quanitification to only monic matches

source
Catlab.Theories.:⊗Method

Combine two constraints conjunctively, sharing as much of the computation graph as possible (i.e. pushout along the maximum common subgraph)

source
AlgebraicRewriting.Rewrite.Utils.RuleType

Rewrite rules which are (usually) encoded as spans. The L structure encodes a pattern to be matched. The R morphism encodes a replacement pattern to be substituted in. They are related to each other by an interface I with maps: L ⟵ I ⟶ R

A semantics (DPO, SPO, CoNeg, or SqPO) must be chosen.

Control the match-finding process by specifying whether the match is intended to be monic or not, as well as an optional application condition(s)

source
AlgebraicRewriting.Rewrite.Utils.get_matchesMethod

Get list of possible matches based on the constraints of the rule

This function has the same behavior as the generic get_matches, but it is more performant because we do not have to query all homomorphisms before finding a valid match, in case n=1.

source
AlgebraicRewriting.Rewrite.Utils.check_match_var_eqsMethod

A match may be invalid because two variables (which are to be assigned different values via the I -> R map) are identified (due to merging via the I->L map, which morally ought be monic but is not for AttrVars). We can check this before computing the pushout to make sure that we will not get an inconsistent result when trying to compute it. This requires executing the custom exprs of the rewrite rule, so we may wish to build in the ability to skip this step if that is computationally intensive.

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
rewrite_match_maps(r::Rule{:DPO}, m)

Apply a DPO rewrite rule (given as a span, L<-I->R) to a ACSet using a match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H

This works for any type that implements pushout_complement and pushout

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
rewrite_match_maps(r::Rule{:CoNeg}, m)

Apply a CoNegation rewrite rule (given as a span, L↩I->R) to a ACSet using a monic match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H where K = ~L ∨ I

This works for any type that implements bi-Heyting logic operators ~ and ∨.

This is described here. Essentially, it is partway between DPO and SPO. Suppose the rule tries to delete two things, one of which satisfies the dangling condition, the other violates it. While DPO would fail to apply at all, and SPO would delete both things (cascading the deletion for the latter), co-negation rewriting would simply delete the item which can be deleted without cascading and ignore the other element.

It includes a quote which indicates that this method should work even when the match morphism isn't monic, if it satisfies the identification condition. Supporting this is not yet implemented.

Match morphisms which bind attribute variables are not monic, hence we this form of rewriting doesn't support VarACSets. Intuitively, it feels like this restriction could be relaxed.

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
rewrite_match_maps(r::Rule{:SqPO},m; pres::Union{Nothing, Presentation}=nothing)

Sesqui-pushout is just like DPO, except we use a final pullback complement instead of a pushout complement.

r.L  r.R

L <-⌞K -> R m ↓ ↓k ↓ r I <- • ->⌜O i o

source
AlgebraicRewriting.Rewrite.PBPO.PBPORuleType
  l    r

L ⟵ K ⟶ R tl ↓ ↓ tk <== tl, tk must be monic L' ⟵ K'

It is assumed we never want the typing/adherence match to be monic, but we can optionally restrict the match L → G to be monic.

We can attach application conditions to both the match morphism as well as the adherence morphism. Until morphism search under constraints becomes efficient, it's sometimes needed to just directly state the adherence morphism as a function of the match morphism.

source
AlgebraicRewriting.Rewrite.PBPO.partial_abstractMethod

This construction addresses the following problem: ideally when we 'abstract' an ACSet from X to A->X, maps into X, say B->X, can be canonically pulled back to maps B->A which commute. However, A won't do here, because there may not even exist any maps B->A. If B has concrete attributes, then those cannot be sent to an AttrVar in A. Furthermore, if B has multiple 'references' to an AttrVar (two different edges, each with AttrVar(1), sent to two different edges with the same atttribute value in X), then there is no longer a canonical place to send AttrVar(1) to in A, as there is a distinct AttrVar for every single part+attr in X. So we need a construction which does two things to A->X, starting with a map B->X. 1.) replaces exactly the variables we need with concrete values in order to allow a map B->A, 2.) quotients variables in A so that there is exactly one choice for where to send attrvars in B such that the triangle commutes.

Starting with a map L -> G (where G has no AttrVars), we want the analogous map into a "partially abstracted" version of G that has concrete attributes replaced with AttrVars EXCEPT for those attributes which are mapped to by concrete attributes of L. Likewise, multiple occurences of the same variable in L correspond to AttrVars which should be merged in the partially-abstracted G.

For example, for a schema with a single Ob and Attr (where all combinatorial maps are just {1↦1, 2↦2}):

  • L = [AttrVar(1), :foo]

  • G = [:bar, :foo, :baz]

  • abs(G) = [AttrVar(1), AttrVar(2), AttrVar(3)]

  • expected result: [AttrVar(1), :foo, AttrVar(2)]

    L -> Partial_abs(G) ↓ ↑ G <- abs(G)

This function computes the top arrow of this diagram starting with the left arrow. The bottom arrow is computed by abstract_attributes and the right arrow by sub_vars. Furthermore, a map from Partial_abs(G) to G is provided.

This is the factorization system arising from a coreflective subcategory.

(see https://ncatlab.org/nlab/show/reflective+factorization+system and https://blog.algebraicjulia.org/post/2023/06/varacsets/)

source
AlgebraicRewriting.Rewrite.Utils.get_matchesMethod

PBPO matches consist of two morphisms. First, a match m: L → G, and secondly a typing G → L′. With attributes, it is not so simple because G has concrete values for attributes and L′ may have variables. Therefore, we actually change the typing to map out of A, an abstracted version of G (with its attributes replaced by variables). So we lift matches L->G to matches L->A, then search α∈Hom(A,L′).

In general, we want α to be uniquely determined by m, so by default α_unique is set to true.

 m

L⌟ ⟶ G || ↓ α L ⟶ L′ tl

 m

L ⟶ G tl ↓ ↘a ↑ (abs = partial abstraction. Note a is Labs in the code.) L′⟵ A α

The "strong match" condition we enforce is that: tl⁻¹(α(A)) = a⁻¹(A). This means we can deduce precisely what m is by looking at α.

source
AlgebraicRewriting.Rewrite.Utils.rewrite_match_mapsMethod
         r
       K ----> R
-gₗ    u ↓ gᵣ ⌜ ↓ w

Gₗ <–– Gk ––> Gᵣ α ↓ ⌞ ↓ u' L′ <– K′ tₗ

For the adherence morphism α to be valid, it must satisfy a condition with m, tₗ. This is checked for matches provided by get_matches, so by default we do not check it.

L <–⌞• m ↓ ↓ G ⟵ Gk

See Lemma 7.2 of "TERMINATION OF GRAPH TRANSFORMATION SYSTEMS USING WEIGHTED SUBGRAPH COUNTING" by Overbeek and Endrullis (2023)

source

Schedules

AlgebraicRewriting.Schedules.PolyModule

Mealy machines (augmented with monadic output) are a user-friendly format for specifying a behavior tree. Behavior trees in general are not finitely expressible, but we focus on trees which can be lazily generated by functions.

Although it is conceptually simple to think of a single set of "input doors" out "output doors" to enter/leave the Mealy machine, such that a Mealy machine has type A → B, we use Σᵢ Aᵢ → Σⱼ Bⱼ, where Aᵢ and Bⱼ are Julia types. This allows us to represent a Mealy machine with (Int + String)-many input doors, for example.

source
AlgebraicRewriting.Schedules.Poly.BTreeType

Lazily grown behavior tree induced by a Mealy machine. The future behavior is dictated by the inputs seen thus far (i.e. a vector of WireVals).

Each vertex is identified by a sequence of inputs and has a state of the Mealy machine associated with it.

Each nonempty sequence of inputs has a MealyRes associated with it.

source
AlgebraicRewriting.Schedules.Poly.MealyType

A function that maintains a state (initially s0) and has monadic output for some polynomial monad t.

The function f must be of type S × WireVal → S × (t ◁ WireVal)

                            (i.e. S × Wireval → MealyRes)
source
AlgebraicRewriting.Schedules.Poly.MealyResType

Output of a Mealy machine

newS - The new state of the Mealy machine mval - outputs along with their monadic values (e.g. probability weights) msg - A message reporting something about the computation

source
AlgebraicRewriting.Schedules.Poly.PMonadType

Quotes in this docstring and others taken from David Spivak: https://topos.site/blog/2023/09/powers-of-polynomial-monads/#exponentiating-monads

"A polynomial monad is a polynomial functor t with coherent maps η: y → t and μ: t ◁ t → t.

Polynomial monads can be thought of as offering compositional (possibly labeled) packages with some number of slots. The compositionality of this packaging says that (via the monad unit) we know how to package up a given element of any set, and that (via the monad multiplication) we can take a package of packages and simplify it to a single package."

We consider monads t of the form: t = Σ_{i ∈ t(1)} y^{t[i]}

I is the type of labels, e.g. probability weights.

source
AlgebraicRewriting.Schedules.Poly.SimulatorType

Equips a wiring diagram description of a simulator with mutable data structures (now behavior trees for each box, but possibly incremental homomorphism caches in the future). Requires that all the boxes of the WiringDiagram be convertable to BTrees.

source
AlgebraicRewriting.Schedules.Poly.apply_scheduleMethod

In theory applying a schedule should result in a list of ACSets associated with out ports and monad labels (e.g. probabilities), and if one were to want to recover the trajectory of the output one would have to use a Writer monad of some sort. For simplicity, the application of a schedule will simply return the trajectories themselves (monadic multiplication could in principle condense this output to the pure output).

source
AlgebraicRewriting.Schedules.Basic.StrengthenType

Adds to both agent and the state of the world via a pushout.

    Agent₁  →  Agent₂
+gₗ    u ↓ gᵣ ⌜ ↓ w

Gₗ <–– Gk ––> Gᵣ α ↓ ⌞ ↓ u' L′ <– K′ tₗ

For the adherence morphism α to be valid, it must satisfy a condition with m, tₗ. This is checked for matches provided by get_matches, so by default we do not check it.

L <–⌞• m ↓ ↓ G ⟵ Gk

See Lemma 7.2 of "TERMINATION OF GRAPH TRANSFORMATION SYSTEMS USING WEIGHTED SUBGRAPH COUNTING" by Overbeek and Endrullis (2023)

source

Schedules

AlgebraicRewriting.Schedules.PolyModule

Mealy machines (augmented with monadic output) are a user-friendly format for specifying a behavior tree. Behavior trees in general are not finitely expressible, but we focus on trees which can be lazily generated by functions.

Although it is conceptually simple to think of a single set of "input doors" out "output doors" to enter/leave the Mealy machine, such that a Mealy machine has type A → B, we use Σᵢ Aᵢ → Σⱼ Bⱼ, where Aᵢ and Bⱼ are Julia types. This allows us to represent a Mealy machine with (Int + String)-many input doors, for example.

source
AlgebraicRewriting.Schedules.Poly.BTreeType

Lazily grown behavior tree induced by a Mealy machine. The future behavior is dictated by the inputs seen thus far (i.e. a vector of WireVals).

Each vertex is identified by a sequence of inputs and has a state of the Mealy machine associated with it.

Each nonempty sequence of inputs has a MealyRes associated with it.

source
AlgebraicRewriting.Schedules.Poly.MealyType

A function that maintains a state (initially s0) and has monadic output for some polynomial monad t.

The function f must be of type S × WireVal → S × (t ◁ WireVal)

                            (i.e. S × Wireval → MealyRes)
source
AlgebraicRewriting.Schedules.Poly.MealyResType

Output of a Mealy machine

newS - The new state of the Mealy machine mval - outputs along with their monadic values (e.g. probability weights) msg - A message reporting something about the computation

source
AlgebraicRewriting.Schedules.Poly.PMonadType

Quotes in this docstring and others taken from David Spivak: https://topos.site/blog/2023/09/powers-of-polynomial-monads/#exponentiating-monads

"A polynomial monad is a polynomial functor t with coherent maps η: y → t and μ: t ◁ t → t.

Polynomial monads can be thought of as offering compositional (possibly labeled) packages with some number of slots. The compositionality of this packaging says that (via the monad unit) we know how to package up a given element of any set, and that (via the monad multiplication) we can take a package of packages and simplify it to a single package."

We consider monads t of the form: t = Σ_{i ∈ t(1)} y^{t[i]}

I is the type of labels, e.g. probability weights.

source
AlgebraicRewriting.Schedules.Poly.SimulatorType

Equips a wiring diagram description of a simulator with mutable data structures (now behavior trees for each box, but possibly incremental homomorphism caches in the future). Requires that all the boxes of the WiringDiagram be convertable to BTrees.

source
AlgebraicRewriting.Schedules.Poly.apply_scheduleMethod

In theory applying a schedule should result in a list of ACSets associated with out ports and monad labels (e.g. probabilities), and if one were to want to recover the trajectory of the output one would have to use a Writer monad of some sort. For simplicity, the application of a schedule will simply return the trajectories themselves (monadic multiplication could in principle condense this output to the pure output).

source
AlgebraicRewriting.Schedules.Conditionals.ConditionalType

A primitive box in a NestedDWD which does not change the state but redirects it out of one of n wires.

It contains a function (A->X) -> ℝⁿ. This optionally depends on the internal state. This weights probability for n outports, conditional on the status of an ACSet. If the function just depends on X rather than the whole morphism, withagent is false. If the function does not depend on the internal state (assumed to be true iff initial state is nothing), then withstate is false.

The state and update function are by default trivial.

source
AlgebraicRewriting.Schedules.RuleApps.RuleAppType

Has the semantics of applying the rule to some match that is found (no guarantees on which one, which should be controlled by application conditions). If rewrite occurs, exit mode 1, else exit mode 2.

The agent is related to the L and R patterns of the rule. This can be done via a Span, or implicitly as a homomorphism into "I" of the rewrite rule, and alternatively just from the shape of the agent alone (if it is identical to I, take the id map, otherwise take the unique morphism into I).

source
AlgebraicRewriting.Schedules.Queries.QueryType

Has an A input/output and a B input/output (by default, the B input can be changed to some other type if needed).

A  R ---------↖
-↓  ↓          []

⌜–––-⌝ [] | Query | [agent subroutine] ⌞–––-⌟ [] ↓ ↓ ↓ [] A B ∅ [] ↘–––––-↗ Performs one action per element of Hom(B,X), optionally with some constraints. (i.e. sends you out along the B wire with agent Bₙ->X).

After you have done this for all Bₙ, then you exit the A port (you need to update the A->X map, and, if at any point the agent was deleted, then you exit a third door typed by 0).

A constraint optionally will be applied to (1) the A->W<-B cospan of old agent and purported new agent. (the new agent is the first argument to the constraint)

source

CategoricalAlgebra

AlgebraicRewriting.CategoricalAlgebra.FinSets.id_conditionMethod

Check identification condition for pushout complement of finite sets.

The identification condition says that the functions do not map (1) both a deleted item and a preserved item in L to the same item in G or (2) two distinct deleted items to the same item. It is trivially satisfied for injective functions.

Returns pair of iterators of

(1) a nondeleted item that maps to a deleted item in G (2) a pair of distinct items in L that are deleted yet mapped to the same item in G.

source
AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complementMethod

Compute a pushout complement of finite sets, if possible.

Given functions $l: I → L$ and $m: L → G$ to form a pushout square

l

L ← I m ↓ ↓k G ← K g

define the set $K := G / m(L / l(I))$ and take $g: K ↪ G$ to be the inclusion. Then the map $k: I → K$ is determined by the map $l⋅m: I → G$ from the requirement that the square commutes.

Pushout complements exist only if the identification condition is satisfied. An error will be raised if the pushout complement cannot be constructed. To check this in advance, use can_pushout_complement.

source
AlgebraicRewriting.CategoricalAlgebra.CSets.check_pbMethod

Y i↘ f_ X → • g_ ↓ ⌟ ↓ f • → • g

Check whether (X, f,g) is the pullback of (f,g), up to isomorphism (i.e. the pullback of f and g produces (Y,π₁,π₂), where Y is isomorphic to X and i⋅f_ = π₁ & i⋅g_ = π₂.

source
AlgebraicRewriting.CategoricalAlgebra.CSets.sub_varsFunction

Given a value for each variable, create a morphism X → X′ which applies the substitution. We do this via pushout.

O –> X where C has AttrVars for merge equivalence classes ↓ and O has only AttrVars (sent to concrete values or eq classes C in the map to C.

subs and merge are dictionaries keyed by attrtype names

subs values are int-keyed dictionaries indicating binding, e.g. ; subs = (Weight = Dict(1 => 3.20, 5 => 2.32), ...)

merge values are vectors of vectors indicating equivalence classes, e.g. ; merge = (Weight = [[2,3], [4,6]], ...)

source
AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complementMethod

Compute pushout complement of attributed C-sets, if possible.

The pushout complement is constructed pointwise from pushout complements of finite sets. If any of the pointwise identification conditions fail (in FinSet), this method will raise an error. If the dangling condition fails, the resulting C-set will be only partially defined. To check all these conditions in advance, use the function can_pushout_complement.

In the absence of AttrVars, K is a subobject of G. But we want to be able to change the value of attributes. So any variables in I are not concretized by the I->K map. However, AttrVars may be merged together if m: L -> G merges parts together.

source
AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_Method
composeH_(r₁, r₂)

compose two rewrite rules horizontally (via pushouts) as shown below: L₁₋₍ₙ₋₁₎-> L <- Lₙ X₁ -> X <- X₂₋ₘ L₁₋₍ₙ₋₁₎ -> L +Lₙ X <- X₂₋ₘ ↑ λ ↑ ↑ ↑ ↑ χ ↑ ↑ ↑ ↑ I₁₋₍ₙ₋₁₎-> I <- Iₙ ∘h Y₁ -> Y <- Y₂₋ₘ = I₁₋₍ₙ₋₁₎ -> I +Iₙ Y <- Y₂₋ₘ ↓ ρ ↓ ↓ ↓ ↓ ζ ↓ ↓ ↓ ↓ R₁₋₍ₙ₋₁₎-> R <- Rₙ Z₁ -> Z <- Z₂₋ₘ R₁₋₍ₙ₋₁₎ -> R +Rₙ Z <- Z₂₋ₘ

source
AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_Method
composeV_(r₁, r₂)

compose two rewrite rules vertically with pullbacks, as shown below: L₁₋ₙ -> L ↑ ↑ I₁₋ₙ -> I ↓ ↓ L₁₋ₙ -> L R₁₋ₙ -> R ↑ ↑ ∘v = I₁₋ₙ ×ᵣ₁₋ₙ Θ₁₋ₙ -> I ×ᵣ Θ Λ₁₋ₙ -> Λ ↓ ↓ ↑ ↑ Ω₁₋ₙ -> Ω Θ₁₋ₙ -> Θ ↓ ↓ Ω₁₋ₙ -> Ω

source
AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_pushout_complementMethod

Initial data: 4 structured cospans + 3 cospan morphisms: μ, λ, ρ g G₁₋ₙ –> G ↑ l ↑ μ L₁₋ₙ –> L ↑ i ↑ λ I₁₋ₙ –> I ↓ r ↓ ρ R₁₋ₙ –> R

Computed data: 2 new structured cospans + 4 cospan morphisms: γ, η, ik, rh G₁₋ₙ G ↑ k ↑ γ ik I₁₋ₙ -> K₁₋ₙ –> K <– I ↓ h ↓ η rh R₁₋ₙ -> H₁₋ₙ –> H <– R In the context of the legs of a multicospan, the indices 1-n refer to the n legs of the cospan. In the context of a map of multicospans, there are 1-(n+1) maps, with the first one designating the map of the apexes. Hence it can make sense to have the elements: zip(legs, maps[2:end]) = [(legᵢ, mapᵢ), ...]

source
Catlab.CategoricalAlgebra.HomSearch.homomorphismsMethod

Find homomorphisms between structured cospans. These are constrained to be iso on the legs of the cospans. Solving this w/ homomorphism finding requires a dynamic acset, and the current hack will be replaced once those are available.

A homomorphism backend that uses SAT/SMT would also make this viable to do without hacking.

source
AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_universal_propertyMethod

A partial function is defined by the following span: m f A ↩ X → B

We compute ϕ(m,f): A ⟶ T(B) such that the following is a pullback square: f X ⟶ B m ↓ ↓ η(B) A ⟶ T(B) ϕ

Essentially, ϕ sends elements of A to the 'real' values in T(B) when A is in the subobject picked out by X. When A is 'deleted', it picks out the right element of the additional data added by T(B).

source
AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_homMethod

Because the functorial embedding of objects keeps a copy of the original data, what to do with morphisms is just carry them along. Because our implementation adds all of the additional stuff afterwards, index-wise, we can use literally the same data for a morphism lifted from X⟶Y to T(X)⟶T(Y).

However, we still need to map the extra stuff in T(X) to the proper extra stuff in T(Y).

source
AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_obMethod

A functor T, playing the role of Maybe in Set, but generalized to C-Sets.

When called on the terminal object, this produces the subobject classifier: See Mulry "Partial map classifiers and cartesian closed categories" (1994)

This function specifies what T does on objects. The key properties:

  1. for all X ∈ Ob(C), η(X):X⟶T(X) is monic. m f ϕ(m,f)
  2. for each span A ↩ X → B, there exists a unique morphism A ⟶ T(B) such that (m,f) is the pullback of ϕ(m,f),η(B))

Not only do we add an extra element to each component of the C-Set, but we need to consider the possibility that a component (with n outgoing morphisms) has any combination of the targets of those morphisms deleted (like the subobject classifier, there are different ways for something to be deleted).

For example, in Graph, an edge can be deleted that goes between any two vertices of the graph. We can't map all deleted edges to the same point in T(E) (if we're going to satisfy that desired property #2), so we need an extra edge in T(E) for every possibility (from V1 to V2, from V1 to V3, ..., from [Deleted] to V1, ..., from V2 to [Deleted], ... from [Deleted] to [Deleted]), where [Deleted] is our name for the extra element added to T(V).

                [src]     [tgt]

Thus, T(E) ≅ |E| + (|V|+1) × (|V|+1).

In general, T(X) ≅ |X| + ∏ₕ(|T(codom(h))|) for each outgoing morphism h::X⟶Y

  • the |X| corresponds to the 'real' elements of X
  • the second term corresponds to the possible ways an X can be deleted.
  • This recursive formula means we require the schema of the C-set to be acyclic otherwise the size is infinite (assumes schema is free).
source
+ World₁ -->⌜World₂
source
AlgebraicRewriting.Schedules.Conditionals.ConditionalType

A primitive box in a NestedDWD which does not change the state but redirects it out of one of n wires.

It contains a function (A->X) -> ℝⁿ. This optionally depends on the internal state. This weights probability for n outports, conditional on the status of an ACSet. If the function just depends on X rather than the whole morphism, withagent is false. If the function does not depend on the internal state (assumed to be true iff initial state is nothing), then withstate is false.

The state and update function are by default trivial.

source
AlgebraicRewriting.Schedules.RuleApps.RuleAppType

Has the semantics of applying the rule to some match that is found (no guarantees on which one, which should be controlled by application conditions). If rewrite occurs, exit mode 1, else exit mode 2.

The agent is related to the L and R patterns of the rule. This can be done via a Span, or implicitly as a homomorphism into "I" of the rewrite rule, and alternatively just from the shape of the agent alone (if it is identical to I, take the id map, otherwise take the unique morphism into I).

source
AlgebraicRewriting.Schedules.Queries.QueryType

Has an A input/output and a B input/output (by default, the B input can be changed to some other type if needed).

A  R ---------↖
+↓  ↓          []

⌜–––-⌝ [] | Query | [agent subroutine] ⌞–––-⌟ [] ↓ ↓ ↓ [] A B ∅ [] ↘–––––-↗ Performs one action per element of Hom(B,X), optionally with some constraints. (i.e. sends you out along the B wire with agent Bₙ->X).

After you have done this for all Bₙ, then you exit the A port (you need to update the A->X map, and, if at any point the agent was deleted, then you exit a third door typed by 0).

A constraint optionally will be applied to (1) the A->W<-B cospan of old agent and purported new agent. (the new agent is the first argument to the constraint)

source

CategoricalAlgebra

AlgebraicRewriting.CategoricalAlgebra.FinSets.id_conditionMethod

Check identification condition for pushout complement of finite sets.

The identification condition says that the functions do not map (1) both a deleted item and a preserved item in L to the same item in G or (2) two distinct deleted items to the same item. It is trivially satisfied for injective functions.

Returns pair of iterators of

(1) a nondeleted item that maps to a deleted item in G (2) a pair of distinct items in L that are deleted yet mapped to the same item in G.

source
AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complementMethod

Compute a pushout complement of finite sets, if possible.

Given functions $l: I → L$ and $m: L → G$ to form a pushout square

l

L ← I m ↓ ↓k G ← K g

define the set $K := G / m(L / l(I))$ and take $g: K ↪ G$ to be the inclusion. Then the map $k: I → K$ is determined by the map $l⋅m: I → G$ from the requirement that the square commutes.

Pushout complements exist only if the identification condition is satisfied. An error will be raised if the pushout complement cannot be constructed. To check this in advance, use can_pushout_complement.

source
AlgebraicRewriting.CategoricalAlgebra.CSets.check_pbMethod

Y i↘ f_ X → • g_ ↓ ⌟ ↓ f • → • g

Check whether (X, f,g) is the pullback of (f,g), up to isomorphism (i.e. the pullback of f and g produces (Y,π₁,π₂), where Y is isomorphic to X and i⋅f_ = π₁ & i⋅g_ = π₂.

source
AlgebraicRewriting.CategoricalAlgebra.CSets.sub_varsFunction

Given a value for each variable, create a morphism X → X′ which applies the substitution. We do this via pushout.

O –> X where C has AttrVars for merge equivalence classes ↓ and O has only AttrVars (sent to concrete values or eq classes C in the map to C.

subs and merge are dictionaries keyed by attrtype names

subs values are int-keyed dictionaries indicating binding, e.g. ; subs = (Weight = Dict(1 => 3.20, 5 => 2.32), ...)

merge values are vectors of vectors indicating equivalence classes, e.g. ; merge = (Weight = [[2,3], [4,6]], ...)

source
AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complementMethod

Compute pushout complement of attributed C-sets, if possible.

The pushout complement is constructed pointwise from pushout complements of finite sets. If any of the pointwise identification conditions fail (in FinSet), this method will raise an error. If the dangling condition fails, the resulting C-set will be only partially defined. To check all these conditions in advance, use the function can_pushout_complement.

In the absence of AttrVars, K is a subobject of G. But we want to be able to change the value of attributes. So any variables in I are not concretized by the I->K map. However, AttrVars may be merged together if m: L -> G merges parts together.

source
AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_Method
composeH_(r₁, r₂)

compose two rewrite rules horizontally (via pushouts) as shown below: L₁₋₍ₙ₋₁₎-> L <- Lₙ X₁ -> X <- X₂₋ₘ L₁₋₍ₙ₋₁₎ -> L +Lₙ X <- X₂₋ₘ ↑ λ ↑ ↑ ↑ ↑ χ ↑ ↑ ↑ ↑ I₁₋₍ₙ₋₁₎-> I <- Iₙ ∘h Y₁ -> Y <- Y₂₋ₘ = I₁₋₍ₙ₋₁₎ -> I +Iₙ Y <- Y₂₋ₘ ↓ ρ ↓ ↓ ↓ ↓ ζ ↓ ↓ ↓ ↓ R₁₋₍ₙ₋₁₎-> R <- Rₙ Z₁ -> Z <- Z₂₋ₘ R₁₋₍ₙ₋₁₎ -> R +Rₙ Z <- Z₂₋ₘ

source
AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_Method
composeV_(r₁, r₂)

compose two rewrite rules vertically with pullbacks, as shown below: L₁₋ₙ -> L ↑ ↑ I₁₋ₙ -> I ↓ ↓ L₁₋ₙ -> L R₁₋ₙ -> R ↑ ↑ ∘v = I₁₋ₙ ×ᵣ₁₋ₙ Θ₁₋ₙ -> I ×ᵣ Θ Λ₁₋ₙ -> Λ ↓ ↓ ↑ ↑ Ω₁₋ₙ -> Ω Θ₁₋ₙ -> Θ ↓ ↓ Ω₁₋ₙ -> Ω

source
AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_pushout_complementMethod

Initial data: 4 structured cospans + 3 cospan morphisms: μ, λ, ρ g G₁₋ₙ –> G ↑ l ↑ μ L₁₋ₙ –> L ↑ i ↑ λ I₁₋ₙ –> I ↓ r ↓ ρ R₁₋ₙ –> R

Computed data: 2 new structured cospans + 4 cospan morphisms: γ, η, ik, rh G₁₋ₙ G ↑ k ↑ γ ik I₁₋ₙ -> K₁₋ₙ –> K <– I ↓ h ↓ η rh R₁₋ₙ -> H₁₋ₙ –> H <– R In the context of the legs of a multicospan, the indices 1-n refer to the n legs of the cospan. In the context of a map of multicospans, there are 1-(n+1) maps, with the first one designating the map of the apexes. Hence it can make sense to have the elements: zip(legs, maps[2:end]) = [(legᵢ, mapᵢ), ...]

source
Catlab.CategoricalAlgebra.HomSearch.homomorphismsMethod

Find homomorphisms between structured cospans. These are constrained to be iso on the legs of the cospans. Solving this w/ homomorphism finding requires a dynamic acset, and the current hack will be replaced once those are available.

A homomorphism backend that uses SAT/SMT would also make this viable to do without hacking.

source
AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_universal_propertyMethod

A partial function is defined by the following span: m f A ↩ X → B

We compute ϕ(m,f): A ⟶ T(B) such that the following is a pullback square: f X ⟶ B m ↓ ↓ η(B) A ⟶ T(B) ϕ

Essentially, ϕ sends elements of A to the 'real' values in T(B) when A is in the subobject picked out by X. When A is 'deleted', it picks out the right element of the additional data added by T(B).

source
AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_homMethod

Because the functorial embedding of objects keeps a copy of the original data, what to do with morphisms is just carry them along. Because our implementation adds all of the additional stuff afterwards, index-wise, we can use literally the same data for a morphism lifted from X⟶Y to T(X)⟶T(Y).

However, we still need to map the extra stuff in T(X) to the proper extra stuff in T(Y).

source
AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_obMethod

A functor T, playing the role of Maybe in Set, but generalized to C-Sets.

When called on the terminal object, this produces the subobject classifier: See Mulry "Partial map classifiers and cartesian closed categories" (1994)

This function specifies what T does on objects. The key properties:

  1. for all X ∈ Ob(C), η(X):X⟶T(X) is monic. m f ϕ(m,f)
  2. for each span A ↩ X → B, there exists a unique morphism A ⟶ T(B) such that (m,f) is the pullback of ϕ(m,f),η(B))

Not only do we add an extra element to each component of the C-Set, but we need to consider the possibility that a component (with n outgoing morphisms) has any combination of the targets of those morphisms deleted (like the subobject classifier, there are different ways for something to be deleted).

For example, in Graph, an edge can be deleted that goes between any two vertices of the graph. We can't map all deleted edges to the same point in T(E) (if we're going to satisfy that desired property #2), so we need an extra edge in T(E) for every possibility (from V1 to V2, from V1 to V3, ..., from [Deleted] to V1, ..., from V2 to [Deleted], ... from [Deleted] to [Deleted]), where [Deleted] is our name for the extra element added to T(V).

                [src]     [tgt]

Thus, T(E) ≅ |E| + (|V|+1) × (|V|+1).

In general, T(X) ≅ |X| + ∏ₕ(|T(codom(h))|) for each outgoing morphism h::X⟶Y

  • the |X| corresponds to the 'real' elements of X
  • the second term corresponds to the possible ways an X can be deleted.
  • This recursive formula means we require the schema of the C-set to be acyclic otherwise the size is infinite (assumes schema is free).
source
diff --git a/dev/generated/full_demo/index.html b/dev/generated/full_demo/index.html index b597475..e319f43 100644 --- a/dev/generated/full_demo/index.html +++ b/dev/generated/full_demo/index.html @@ -776,4 +776,4 @@ σ₃ = ACSetTransformation(G3, G3; V=[3, 1, 2]) g′ = find_deps([R3 => M1, R2 => M2 ⋅ σ₃, R1 => M3 ⋅ σ₂]) -@test g′ == g
Test Passed
+@test g′ == g
Test Passed
diff --git a/dev/generated/game_of_life.ipynb b/dev/generated/game_of_life.ipynb index ba6c48c..1311700 100644 --- a/dev/generated/game_of_life.ipynb +++ b/dev/generated/game_of_life.ipynb @@ -299,9 +299,9 @@ "name": "stdout", "output_type": "stream", "text": [ + "| o | x | x |\n", "| x | o | o |\n", "| x | x | o |\n", - "| o | x | o |\n", "\n" ] } @@ -354,9 +354,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "| x. | o | o |\n", + "| o. | x | x |\n", + "| x | o | o |\n", "| x | x | o |\n", - "| o | x | o |\n", "\n" ] } @@ -384,7 +384,7 @@ { "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}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), 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(\"n4\", \"\", \"\"), 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(\"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(\"n5\", \"\", \"\"), 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(\"n6\", \"\", \"\")], 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(\"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(\"n6\", \"\", \"\"), 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(\"n6\", \"\", \"\"), 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(\"n7\", \"\", \"\"), 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(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], 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}}(:margin => \"0\", :shape => \"circle\", :style => \"filled\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:dir => \"none\", :minlen => \"1\"))", + "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}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n2\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n3\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n4\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n5\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n6\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n7\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"red\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n8\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), Catlab.Graphics.Graphviz.Node(\"n9\", OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:fillcolor => \"green\", :label => \"\")), 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(\"n4\", \"\", \"\"), 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(\"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(\"n5\", \"\", \"\"), 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(\"n6\", \"\", \"\")], 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(\"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(\"n6\", \"\", \"\"), 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(\"n6\", \"\", \"\"), 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(\"n7\", \"\", \"\"), 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(\"n8\", \"\", \"\"), Catlab.Graphics.Graphviz.NodeID(\"n9\", \"\", \"\")], 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}}(:margin => \"0\", :shape => \"circle\", :style => \"filled\"), OrderedCollections.OrderedDict{Symbol, Union{String, Catlab.Graphics.Graphviz.Html}}(:dir => \"none\", :minlen => \"1\"))", "image/svg+xml": [ "\n", "\n", "\n", "n1\n", - "\n", + "\n", "\n", "\n", "\n", @@ -415,7 +415,7 @@ "\n", "\n", "n4\n", - "\n", + "\n", "\n", "\n", "\n", @@ -425,7 +425,7 @@ "\n", "\n", "n5\n", - "\n", + "\n", "\n", "\n", "\n", @@ -435,7 +435,7 @@ "\n", "\n", "n3\n", - "\n", + "\n", "\n", "\n", "\n", @@ -480,7 +480,7 @@ "\n", "\n", "n7\n", - "\n", + "\n", "\n", "\n", "\n", diff --git a/dev/generated/game_of_life/index.html b/dev/generated/game_of_life/index.html index ccd05de..8cc6a5a 100644 --- a/dev/generated/game_of_life/index.html +++ b/dev/generated/game_of_life/index.html @@ -763,4 +763,4 @@ | o | o | o | x | x | | o | x | x | o | x | | o | o | o | x | x | -| x | o | o | o | x |

Visualize the results in the traj folder

view_traj(L, res[1:10], view_life; agent=true)
+| x | o | o | o | x |

Visualize the results in the traj folder

view_traj(L, res[1:10], view_life; agent=true)
diff --git a/dev/generated/lotka_volterra/index.html b/dev/generated/lotka_volterra/index.html index 124e8b4..8d2757e 100644 --- a/dev/generated/lotka_volterra/index.html +++ b/dev/generated/lotka_volterra/index.html @@ -851,4 +851,4 @@
'/>

Run the simulation for 100 steps

res = interpret(overall, X; maxstep=100);
┌ Warning: Exceeded maximum number of steps
-└ @ AlgebraicRewriting.Schedules.Eval ~/work/AlgebraicRewriting.jl/AlgebraicRewriting.jl/src/schedules/Eval.jl:72

Visualizing the results

Run this line to view the trajectory in the generated traj folder

view_traj(overall, res[1:10], view_LV; agent=true, names=F2(N));
+└ @ AlgebraicRewriting.Schedules.Eval ~/work/AlgebraicRewriting.jl/AlgebraicRewriting.jl/src/schedules/Eval.jl:72

Visualizing the results

Run this line to view the trajectory in the generated traj folder

view_traj(overall, res[1:10], view_LV; agent=true, names=F2(N));
diff --git a/dev/generated/ptg_simple/index.html b/dev/generated/ptg_simple/index.html index b25ec4e..15e77b8 100644 --- a/dev/generated/ptg_simple/index.html +++ b/dev/generated/ptg_simple/index.html @@ -438,4 +438,4 @@

Apply Rule - + diff --git a/dev/index.html b/dev/index.html index 884da23..0f0aead 100644 --- a/dev/index.html +++ b/dev/index.html @@ -73,4 +73,4 @@ end

6. Identify the match from the rule to the state

This can be done manually or automatically.

  • To manually identify the match, fully-specify an ACSet transformation. For this example, we would like to rule to swap p2::Player and p3::Player
pattern_match = ACSetTransformation(L, state, Player=[2, 3], Member=[2, 3], 
                                     Team=[1, 2], Name=["Alex", "Casey"])
  • To automatically identify the match, use the backtracking search algorithm provided by AlgebraicRewriting. This may return multiple matches, so you can provide logic for deciding which match to select.
pattern_match = homomorphism(L, state; initial=(Name=["Alex", "Casey"],))
 
-matches = get_matches(rule, state)# get all four possible matches, then pick one

7. Apply the rewrite rule

This executes the rewrite process using using the defined rule and match.

result = rewrite_match(rule, pattern_match)

Authors

This documentation is maintained by Angeline Aguinaldo and Kristopher Brown.

+matches = get_matches(rule, state)# get all four possible matches, then pick one

7. Apply the rewrite rule

This executes the rewrite process using using the defined rule and match.

result = rewrite_match(rule, pattern_match)

Authors

This documentation is maintained by Angeline Aguinaldo and Kristopher Brown.

diff --git a/dev/objects.inv b/dev/objects.inv index 8526e3d71557cab09c34467b51c43d85f0be69fc..4e63dd5f5984a567fcb9b4e05fa97e4bad5b2035 100644 GIT binary patch delta 4469 zcmV-*5sL1_BhVv|O#wBLPCI{H+j88v5q+PpKhyO>)qU#;yBwqXD_TgTJ9Lat<6~ zBV!k#nYYAqYPt3${z~1*^_P=R-e`$^OsxnzPZk@`GabApDpkqPPtboGctpqWs8BDh zH8#n@^xOq5XP}mNf{uv))w=z2h~C0yL>A~2J}dk@5`DJJ8{$QnQmdR}w#*ZB%HGij z`K~YvqNN$S>%glJE&croy7F8bqeF@zIPt^C@*`IW{_|fgJH*j1*=in_mK{%DjGz9>%a5loktl;QWl+p- z#K*<>ppIopD{`X=U6UJ6+4Dxy^I1-8bQn=#d`|Hq((gdv0OfyWKRufm$9UoT*oaox zaD5mV%QK*n5uW6_=_mATf<$2ig^?_bMB&kkiSd?N!O93Iv2hq;z1i_%f;bsU$VM~6 zfw^he*z=4zw#gcYhUK|8Am3tP;BS^4dAG)%0iR%v8$NcIt2v>S^<~y2R5?S8KVtlm zbg5@mZ1)I!qW69S}`x%Zn;pn-rw6|Ov*N)WliJUb|6=y~(zec(*j}ffj zO<=tCZ(K@zrV9#U@DfNVF*+k$D=!HBYEh@<0u{ta5{u>ebYff_UYu*K$EOp-%Kl}< z5S(!wW4$J_6z`n~qb3xAai&YHC}0s5L5|8rAhJd zk}c^luqtP1nPCAk2B;a?D2CYvgV~JPX^hVs*SH`ZPoL+A%aQxX^UKp?VJZ8YhlQTe! zK{C83B4U0p25dP(2Za&c*irQafrXfqO6SQ(;@yD4XNoeEx<<48f|6@WPC2^dI0w2x zn}sntf?t+|f+ylhU$MeizQbOCsj=AjcCCM(lSh_<4kdJ~!HaI#hf!vr&n4JB;%w{= zuty~=GHcU=fKINyXs&bsDXi@1<;1wA)+cO71iTg<%9j(AQgE9XMbw>dK%?DQ)D?zb zhY>T9F)2z&N3%_|D)cJ z5bID_KqZ`$woi`YaEj%Hldmh+!)AXde>AQ)Fum^LvO55CgkHKwpS*)LhDG2Y*OjvJOayKbTT55@4V5QHY=PBz)ug;24CHU=yy$hPh)*(J|m6djn`-@|TjrL^yUWaEI1x;<0uy zrF~(!^bR!mqsQU1=Z|*KJF>n-Vxe_+E1!omo`18;vg{996R?`XU?YuODM?oCtV_s9h;ummTYLq&jdzx%M# z@5I1f-|ryt#AXnGfZ~H@P2b z#1h@0^z(Inmk6Y5xqcKX&)t`gkj(XOFpW$%B#cvxDcdPW8%&eQal3z9cnnu{QjmF0 ztS^DrAWHJx_f(SadMnA?^b_ogayE`o#;k697yS3N>RV(!> z>W!nJ66ZA)pUuNdu1T~JVNG=m5NcMawo-GQtUn7lT`_X+!8LLC;||I{hrFDi0|8*p z*wL|TM`}qZ@cLUoTMl}Il(mDN)-Ar5y@wgfn5Wu?0&QHFwMKt;4yDatgEI?)aI&&O zRdL^eZiA9LW$6P|Q)*DPTqPKDs<>!!O0}DS8aljMF9H<2!WOkx6VRjZ9}QM+xDFdN zc?HOBNl>jt+lpGN{A-|aTOv&_7giGfV0oIrFdp4A7kmU}lqPKB%Y<1H&)m1OYbNFy zaWIVkh1?e7k;i|`TRZ(%Ss(PKZjHJ#D@aC~uoU#D}1@0Ai+Qs{pJfDa@}jMtFe60g{+i}PeS zWGtdxoaJoeMK1G_?#|~tCbENG9f*{t8Ku^3ctj{vlYWpOWqL15?fq-Zwo(@HuZT0;|1wY< zwAjEwBA~mP0nptf{yCn$(CvaG^uhSP)S9JQ(Iys6GArZXX`m~mdr`c~zRT`shE zj^~}eCOdT(5sTt=M}AubM$H0uM1_OnCVgOQdsY~_3l{^li>#(8tndBzlb~*9YKCYP zhbP&}Rl`pwN%%=|##kt={PPaFI3vF009^vcPP+SGS&qgeZGI z4x$JpA#7YQH{Odee%c~HuFDkUeX6d;E=m~RFkj4yR+_MZ>!87qK(2O8B#rx_YP z=eL7uF|!b%{o-7D8~8o-p_&8k8rd@Y<=Ha(po(i!AbKj@+V%{S7PGIL7PFt|+`5zx z9j%(P{Q^I9vfOMF6@Lq;Id`FNppO9RX>8mMvwK@!ar$t=dWmfZ2%b})Zi zqw?(st(!6a#&>Tp4Vn3&pkrus`yhS2LEH9F+`@`X8F#@oSiCnSqYiO~>sFI=GF3BA zMu{FIDYkubc1m*|#3nQwz3j%y5qXc7_kA-e3fwbWCA^MYvPdt{<7C!th#m9R7gmK= z7JNxoH$OPqJZ`rT;pV(Z=M{ca!Igg&$L>wXRu(R~r zh8;a-#;to8MzNa_35ZGNNvOPsV_wO%;cP=8K=sw7*aU|z=Zk3PJfyF!{PQL`(#6w3 zl6GEt#v%iXs6JoQseKLX3rB0}#cr7it-2hiiOW%w{#4+V|H9eyWRPg#(`|obf9JiO z(}K6tNBj)KAsFQq-f7FALb#d3x}jlv^VKM+@Nga^s9g+)sCDY_kmV|i&;5e~XhTaII5XIZri#F&d$Sxf(&o=kYoGck)AKnqEAeDL-G+flx<(;8zii8w z`Q=+aB9g0UYX?NK8l}&cLs>TIgO9kCr=32CP+BDukzBsbUF#%FzQunH<6QJxYw__t zQV~S@0a?qM!hF}XWz`I?F*d^uoygdqM``#0mIVAzb z(E#z14z0bb-PNu9^~`^wpJ(AQ_Am&gJIM7dA0R^0X|xZU_j>EgWcs4R>;W9iVmclC z?d&}Q>-8qmPAqG+kt1x)Hn(w9)1en`%ub;{{c%^%c)I%sT0r@;7T^S7e;KW`&s*f8 z3a73(=AjwX*YxbB`B15;5i9+n`(k=7v8jYw%^_XkX<3}rY!QEGeOOycy@R>Jmp4n} zxn?g2+Ggii8-O-!AeY%Io-#QH;KZ_vl1nm#4TFg)@#up9q9vm8J2-@}av^nGL%<%nh|1G#E~sgW(-5l$z6*MsLwDtT#{^ah3NsOl&vV+ zKTMnLFRg8Ysy@r4IJ4Nv^n1Xfe3kJ@mZt2(!z*c5!qR^;EVXfl{)zM9aM+6*{20hR}S;99vATls(ZBKg=6{+9A;fWpeX+l>Z3&%fce z?)o9>8ChsZ0_v3h@=%T^c20t6k$qIjeBsV9?U6;)6MU-G4}7GtOG-;eOVB<=rQMyo zJT-*HK-(lnS9YSjtNq7Z%2+PKmWDpFM=kzx=YUC{Re`QfyWk73B`ov3Nz;kQVlTaw zt*U9Au9AVx);W)2!!-Hpa=K787Mvf12G|I$h`bBrS%<}1-~vs1)@D5>e|^PqLj@Ig z{v$3a8|{-$zilvgklDYwUQ}=3hPYdTOS5G5I0a9hDabEa8 H^=`Q&%Sn>4 delta 4457 zcmV-v5ti=IBg7++O#w8KPCI`c+j85u^<7_qCadZ0)Ku1TY$ut0sBGursU3T5Z}O<2 zNJwHr5nPb6qk8-Ueed-D`XxQMkOV1^1WC#9ww;~XkQC0rA#m>Jfc63xe?w91zHy0z ztX+gg{tQp3?KxNYj(V{d%m!cl-V6tr+A(%tOqaetcJYF!P@11#pm%?8iB8~Bfu7k5 zJSNkz?@h5DfjZ&^IwrxLz4~*6-os-=rsxbFEBJg8f3?TA#E&thwjN`C%nNkJ?$IZC zuOJKK**NkRp#dB&-pF!+ zH!TPIzBR!PS>VXBeeV|Nn@%nK&30mcW$jt;2xQy}us54e2rZp2Czmkg2r>MK;YSib z;`kBZM-o5ULjr$4O7Zt7&O`-s2A&-fxO4JVb5{o#drjMQk|0~bg^2HtZZ-}^fwlJlb(_kw>!sGx$CfrCNcffz4+Y_?u} zJYwT}d#ONDxV1u?7Pk(@@1=ss1|dGEC#;@cXIQ-x9C@?AvMnlxarA45#VBMWIf~=& z9TVSMc(FyM03A{s0aw@)A2asS=-08s#uv4$DH28T3Peo(mI5PBr;#NEslXmDDQzpT z3|1qs9A$qZuqlsQGcG&LIUI4o-l4FxE3ShgT5mY8j={T& zg-wr~IbPUSyb9NuXgEM(BG*uwLS3Tg=U7$j%b~yjI2qXn%NE0M>i%pD(V?POR&j(al>kS~&pX07YZm z+!TKnY;tN4!8Jd1*@LOrt%V&sb8AY;BHcVICV~+dldbI}c;^WMzMmWcVhGahMKKZl z!4NQUgawLXx^&`l1_41#M`e8SnfSM$@R_2Fq^>c1e*wugC5P-?aX$x^!5D?rJBD9o zghC|Z%UH3*Sbo5Mh^aMQ22N$1Q}iqa97=!T*b7hF`92IX=lWcM-6QVOY2o&$pzFw* ztRQ$N*S{M|Iyfn8Z145Jx}o+L?8F4378A(V1C&8hTjAcGm;4? zNwW{vZT_atS#Se>Xoul(wy`@DF#${HPO;<5{@Vcq_e{j^sWKF zyIf<1REUpBxJqI*P=Tq(W@H%vR0-AqJo5w*`!$K!Ks5@)J#F?$!(wbL4JC*zCsiExJWKow>kQUN6F~^ z@VGzxIhm<{cml6niTslItHIF?#h6jW-4taL>p{N|76MTDvZG+t^zGKM!0P~>Qrg$e z$l#hAx+TT#F<}}Y8aQMTk_dkqOTtKq1Il+HxiX`(&167-GKtuZ^selcWbA)9V9qoD zACFzl_9KD)E%tytW)OXG9|G+BZvn8ty?FndhaDuY7;1jY^8?X<|8p9EyiaWhi`$0> zbT`KoqZ^||sv!Z^BUzUlSOT#o$&;&P;fD&c*cdkKXHFbLQoSU?1+u*$j+AS|b=B;= zpv((yF^$JwL>Q*T*=Qy;4(NZZF?Z-Be=>vHN^**r*jfUvjY!Xj$CREAou#M1egfS( zowYlZ)3?jOgTQVf7Xlda;AJX0Cpd_(ycX{zq^FC1&&>yG!Dq}#M#-!Oy8g3A*#nS+ z@th>D1bYOAu$c8I4C`>Vk9Z>EYGNXYy2GjXH)h@TVjnu1{H%XI82cT~FXcAp< zO=9dSR7}S_1;Yu|w=|TK#aH2HmF(O{@L64cxr2(=5g#YufB@hbCqD6C;1_HgfYLmh zY6k8dgH5RNMpaCzUDA*Uqpq<{o%sL^ApA$exfd#vtB_%6UJ!VPu{Y7lYtl%0d_C!`xjn z!&N#TtfuLVrYnD9v&z62boCbq3UHXHQg5;J?U>LVp4m$oNSKgRc1~b9ofx}?$842b z#U@%}nEFh}k>-iTD=M3qlhs6FUfPrug3j%55Qfx9NaO6=u;toW0ahIFuUr>T$ z{ClF9xO4jEN`O=R) z7T(@pOt@X#LBG5aO-v(7?NxM4C`^+*kly9+L5|){-NFPz-O$~*ZX4yT1kueS0soYe(LB8m%rdf9N}F< zKX^BFgZsl*rc03KtQg+cMqFx?CS+;AM460P&d}$j__YjW2FayTfb(tLSjMuFl(qb2 z89^<57my|At74<8Bg!3Q>S4mltripF?;yd$8}NT<3Z$|;LUs7d*UQ)?7OTsN7S{>i znQO8$ZyK}oYkSXci;ht}!7aVQjr&dJj;-U{QRGcM46a>l*Rim9+NK)?Rh(&} zv^cBg4Nud&p%RR-9H{>B4!S%if$aiZ>WrPXkHPXJDgMUkT9U93oXNa!-4K2uNKUX8 zy_SDdqa{4Yw!gZtgz-3G3MHs%QwW;gT% zQpHkj*dJRI_Yd^>@dFUX#;M$=FN*sIrfGlkgH#w>C5dZ9P*a)l2?@tE>$Q?Uw663N z@X4GL{M0zW9tCb=3-$(nd+6FYvxYraSmARNdV)HUo;0&=gX{#iIkBphw&6)C-TdHa`>c$D zi%Ap5w%PvW|JR+i(53xHsqXw&l%ju%c^-Q;;kg!vh$F-;>QKKf+0kQW+}bB?6uTLd zkc`PBO{{ka<4dvDoNZW3XWe-ek0CB7viufauN|#voQkMwcvnM?voz$W2%gt)6`yc49TB8j_-q?Z{>5nLY%SX9LVkY^;U*9j z72a9H{9v@4fZWii!C8^=zV0=js^SPw#}@JuC#&*sj`>+L`6i$E8Pj{&#%E~k%kcrZ z0wY{VoDD2eTGeQG5RP@RUB@_V2W`9V7`wBwnh`@TZsjc9>q5B+D=R|cJdyf?B%)!Z zrz}^-`o>$QaYB|s$;XB*BaMGNwnDg<8SV8*57Y&X*cSlu21!Rl9k6O{8stIcMSCx3 zT_1Yxr@VdYqD(I)%&a8Le6|e(lhLd2ayOb46OfaKGgG6G=P$<&#5`(~ zvucJHn9lHc#y_9dY9q~%n(kd4{~B1@wn$AZumF_q$!okf91)z6uPQI zKp?nb-`LXb{U4=EKzV<7m_BTodeq|5rXjU`2(`!eiuh}~7pk|YO(*_E^Kg^(2@E{; zHX+6F1`>lU#QMIH;Y)u#x9QhWbb@^hM44){>Nnp&DzcSYJF4ff>M^;ss8N$T?ty@h zB`;efmh#_4SuB>Zald7wiluO>wpp)KeI&EIdY*;;^uH@T{o#M^|BwI`k03#`kAqn} zH$H|`NS~c~;`EbY^~x}XF)Y>u#s)=!?^*yh%l(X%n!Dtl*1tlVrR z414U@OY0%<$H_93B`5!D4`cs+c`=xJ0Y6LZ`xD#wx~Z5j(QqA4I~x$# zA;v1|hz`eqE1FO>?OL5GDf$VtU0V%Pc?>(}gKd-8xqWe+R zl0FLMrt8-hS$;H;D#Lozx=k026xpvo*QN7 z{xY;;Z1;LZe!Yz9VP$KUORTUY;qWosqT-av0k66?+oNk~S0e4vu0mNmT0hvRBSyv9 z>LXA3E+6gL2mX86FI8pJmQ+>t;gp=tP)1gcXjmjwJtui^T=DRvUza#f?VYkB>Ov|! z_0F0f1hju6$9C~JT29F1Oa7FdJ}JC`bAp;Vv$J*OSTRGNKSnYV_p)KHVg=+Z@$ zpXC2OpK#QZu%)ffmF~n}?%ZJ0XIcE;syH}>kdk%2*J(PDaOtGC@>4a_RWjexxaU#S zkIGQk;d>f5at2V|>!-*Cpn0 v1N+z1nJmdW@oJoUTv*lt-uc94XM?tSTDUm5dKy6zkSR-p^TPiD_072wI;OP< diff --git a/dev/search_index.js b/dev/search_index.js index a14e1c9..d23bc90 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"EditURL = \"../../literate/game_of_life.jl\"","category":"page"},{"location":"generated/game_of_life/#Conway's-Game-of-Life","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"This is a demonstration of the game of life as an agent-based model.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We start with importing some libraries.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"using AlgebraicRewriting\nusing Catlab, Catlab.Graphs, Catlab.CategoricalAlgebra, Catlab.Theories\nimport Catlab.Graphics: to_graphviz\nusing Catlab.Graphics.Graphviz: Attributes, Statement, Node, Edge, Digraph\nusing PrettyTables\nusing Luxor","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The game of life has two rules: one which turns living things dead, and one that brings dead things to life. We model the terrain as a symmetric graph: cells are vertices. Neighboring cells have edges between them.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Implementation wise, if we are going to update cells one at a time, we must keep track of two bits of information (the cell's living status for the current timestep and whether it will be alive in the next timestep). Thus we need helper rule to overwrite the \"current\" life status with the \"next\" life status at the end of each timestep.","category":"page"},{"location":"generated/game_of_life/#Ontology","page":"Conway's Game of Life","title":"Ontology","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Defining an ontology is stating what data is required to specify a state of the simulation at some point in time. In AlgebraicJulia, this is done via declaring a Presentation, i.e. a database schema. Objects (Ob, or tables) are types of entities. Homs (Hom, or foreign keys) are functional relationships between the aforementioned entities. AttrTypes are placeholders for Julia types, which are assigned to Ob via attributes (Attr).","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The schema below extends the schema for directed symmetric graphs, which consists in two tables (E and V, for edges and vertices) and two homs (src and tgt, E→V). Furthermore a hom inv: E→E enforces that each edge is paired with its opposite-pointing edge.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The schema below says there are two more types of entities, Curr and Next. Think of these as little tokens that can be assigned to vertices to mark them as currently-alive or to-be-alive-in-the-next-timestep, respectively. Thus, we can also thinking of them as picking out subsets of V via the maps curr and next.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"@present SchLife <: SchSymmetricGraph begin\n (Curr, Next)::Ob\n curr::Hom(Curr, V)\n next::Hom(Next, V)\nend\n\n@acset_type Life(SchLife, part_type=BitSetParts) <: AbstractSymmetricGraph\n\nto_graphviz(SchLife; prog=\"dot\")","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We can further extend this schema with an additional attribute of (x,y) coordinates for every vertex. This is nice for visualization but is otherwise unnecessary when doing the actual agent-based modeling. So what we will do is build our model with the Life schema and then run our model with the LifeCoords schema.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"@present SchLifeCoords <: SchLife begin\n Coords::AttrType\n coords::Attr(V, Coords)\nend\n\n@acset_type AbsLifeCoords(SchLifeCoords, part_type=BitSetParts) <: AbstractSymmetricGraph\n\nconst LifeCoords = AbsLifeCoords{Tuple{Int,Int}};\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#Data-migration-functors","page":"Conway's Game of Life","title":"Data migration functors","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We ought to be able to take a state of the world (with no coordinate information) and obtain a state of the world with coordinates (the canonical way to do this is to assign \"variables\" for the values of the coordinates).","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"F = Migrate(SchLifeCoords, LifeCoords; delta=false); # adds coordinates\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"F⁻¹ = DeltaMigration(FinFunctor(idₒ, idₘ, SchLife, SchLifeCoords)); # removes coordinates","category":"page"},{"location":"generated/game_of_life/#Helper-functions","page":"Conway's Game of Life","title":"Helper functions","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Functions to help us create a grid.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function make_grid(curr::AbstractMatrix, next=nothing)\n n, m = size(curr)\n n == m || error(\"Must be square\")\n X, coords = LifeCoords(), Dict()\n for i in 1:n\n for j in 1:n\n coords[i=>j] = add_vertex!(X; coords=(i, j))\n if Bool(curr[i, j])\n add_part!(X, :Curr, curr=coords[i=>j])\n end\n if !isnothing(next) && Bool(next[i, j])\n add_part!(X, :Curr, curr=coords[i=>j])\n end\n end\n end\n for i in 1:n\n for j in 1:n\n if i < n\n add_edge!(X, coords[i=>j], coords[i+1=>j])\n end\n if j < n\n add_edge!(X, coords[i=>j], coords[i=>j+1])\n end\n if i < n && j < n\n add_edge!(X, coords[i=>j], coords[i+1=>j+1])\n end\n if i < n && j > 1\n add_edge!(X, coords[i=>j], coords[i+1=>j-1])\n end\n end\n end\n X\nend\n\nmake_grid(n::Int, random=false) = make_grid((random ? rand : zeros)(Bool, (n, n)));\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Functions to help us visualize a grid. Although we have no such constraint, we'll expect any LifeCoords instance to be a regular grid (for the purposes of visualization). When that's the case, we can visualize the game state using plaintext.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function view_life(f::ACSetTransformation, pth=tempname())\n v = collect(f[:V])\n view_life(codom(f), pth; star=isempty(v) ? nothing : only(v))\nend\n\nfunction view_life(X::LifeCoords, pth=tempname(); star=nothing)\n n = Int(sqrt(nparts(X, :V)))\n coords = Dict([(i, j) => findfirst(==((i, j)), X[:coords])\n for (i, j) in Iterators.product(1:n, 1:n)])\n mat = pretty_table(String, reduce(hcat, map(1:n) do i\n map(1:n) do j\n c, x = [!isempty(incident(X, coords[(i, j)], x)) for x in [:curr, :next]]\n res = c ? (x ? \"O\" : \"o\") : (x ? \"X\" : \"x\")\n return res * ((star == coords[(i, j)]) ? \".\" : \"\")\n end\n end); show_header=false, tf=tf_markdown)\n open(pth, \"w\") do io\n write(io, mat)\n end\n return mat\nend\n\ninit = make_grid(3, true)\nview_life(init) |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We can also visualize a grid with a distinguished agent. Here an agent living in a game state X is a map A → X where A is the shape of the agent. The only kind of agent we'll consider in this model is that of a lone vertex.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Note that A below is defined without coordinates, whereas init is an instance of LifeCoords. So in order to relate them via a mapping (which requires them to share a schema) we promote A to LifeCoords using the data migration, F.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"A = Life(1)\nview_life(homomorphism(F(A), init)) |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We must also work with miniature game states that are not grids in order for us to define the dynamics, as they are what the patterns and replacements of rewrite rules are made of. In order to visualize these, we will use another visualization function.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function view_life_graph(X::Union{Life,LifeCoords}, pth=tempname(); star=nothing)\n pg = PropertyGraph{Any}(; prog=\"neato\", graph=Dict(),\n node=Dict(:shape => \"circle\", :style => \"filled\", :margin => \"0\"),\n edge=Dict(:dir => \"none\", :minlen => \"1\"))\n add_vertices!(pg, nparts(X, :V))\n for v in vertices(X)\n set_vprop!(pg, v, :fillcolor, isempty(incident(X, v, :curr)) ? \"red\" : \"green\")\n isempty(incident(X, v, :next)) || set_vprop!(pg, v, :penwidth, \"4.0\")\n set_vprop!(pg, v, :label, star == v ? \"*\" : \"\")\n end\n for e in filter(e -> X[e, :inv] > e, edges(X))\n add_edge!(pg, X[e, :src], X[e, :tgt])\n end\n G = to_graphviz(pg)\n open(pth, \"w\") do io\n show(io, \"image/svg+xml\", G)\n end\n G\nend;\n\nview_life_graph(init)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Now we make some helper functions to construct important ACSets and maps between them. We start with a single vertex which is marked as to-be-alive in the next time step.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Next() = @acset Life begin V = 1; Next = 1; next = 1 end;\n\nview_life_graph(Next())","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We also want to refer to a vertex which is alive in the current time step","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Curr() = @acset Life begin V = 1; Curr = 1; curr = 1 end;\nview_life_graph(Curr())","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We also want these where we have a morphism incoming from a vertex.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"to_next() = homomorphism(Life(1), Next());\nto_curr() = homomorphism(Life(1), Curr());\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We make a helper for cells connected to n living neighbors","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function living_neighbors(n::Int; alive=false)\n X = Life(1)\n alive && add_part!(X, :Curr, curr=1)\n for _ in 1:n\n v = add_part!(X, :V)\n add_part!(X, :Curr, curr=v)\n add_edge!(X, v, 1)\n end\n X\nend\n\nview_life_graph(living_neighbors(3))","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We can control whether the central cell is itself alive or not","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"view_life_graph(living_neighbors(3; alive=true))","category":"page"},{"location":"generated/game_of_life/#Rules","page":"Conway's Game of Life","title":"Rules","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We have finished specifying what makes up a simulation state, and next is to define what sorts of transitions are possible. This is done by declaring rewrite rules.","category":"page"},{"location":"generated/game_of_life/#A-dead-cell-becomes-alive-iff-exactly-3-living-neighbors","page":"Conway's Game of Life","title":"A dead cell becomes alive iff exactly 3 living neighbors","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"BirthP1 = living_neighbors(3) # must have 3 neighbors\nBirthN1 = living_neighbors(4) # forbid the cell to have 4 neighbors\nBirthN2 = Curr() # forbid the cell to be alive (i.e. it's currently dead)\nBP1, BN1, BN2 = homomorphism.(Ref(Life(1)), [BirthP1, BirthN1, BirthN2])\nbac = [AppCond(BP1; monic=true), AppCond.([BN1, BN2], false; monic=true)...]\nBirth = Rule(id(Life(1)), to_next(); ac=bac);\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#A-living-cell-stays-alive-iff-2-or-3-living-neighbors","page":"Conway's Game of Life","title":"A living cell stays alive iff 2 or 3 living neighbors","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"PersistR = @acset Life begin\n V = 1; Curr = 1; Next = 1; curr = 1; next = 1\nend\nPersistP1 = living_neighbors(2; alive=true)\nPersistN1 = living_neighbors(4; alive=true)\nDR, DP1, DN1 = homomorphism.(Ref(Curr()), [PersistR, PersistP1, PersistN1])\npac = [AppCond(DP1; monic=true), AppCond(DN1, false; monic=true)]\nPersist = Rule(id(Curr()), DR; ac=pac);\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#remove-\"Curr\"-status","page":"Conway's Game of Life","title":"remove \"Curr\" status","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"ClearCurr = Rule(to_curr(), id(Life(1)));\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#remove-\"Next\"-status","page":"Conway's Game of Life","title":"remove \"Next\" status","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"ClearNext = Rule(to_next(), id(Life(1)));\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#Copy-\"Next\"-to-\"Curr\"","page":"Conway's Game of Life","title":"Copy \"Next\" to \"Curr\"","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"CopyNext = Rule(to_next(), to_curr());\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#Assembling-rules-into-a-recipe","page":"Conway's Game of Life","title":"Assembling rules into a recipe","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Now we can assemble our building blocks into a large wiring diagram characterizing the flow of the overall ABM simulation. In addition to the blue rewrite rule blocks, we have yellow Query blocks which execute subroutines once per agent (the second output wire) before exiting (the first output wire).","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Give symbolic names to the rewrite rules from before","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"rules = [:Birth => Birth, :Persist => Persist, :ClearCurr => ClearCurr,\n :ClearNext => ClearNext, :CopyNext => CopyNext];\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"All rules have interface of a single distinguished cell, i.e. they are executed from the perspective an agent which is a particular distinguished vertex.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Normally we can consider branching possibilities depending on whether or not the rewrite is successful, but in this simulation we don't do this. tryrule simply merges the two output wires from a rewrite rule box into a single output wire.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"rBirth, rPersist, rClearCurr, rClearNext, rCopyNext =\n [tryrule(RuleApp(n, r, Life(1))) for (n, r) in rules]\n\nview_sched(rBirth)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The first for loop is computing next for all cells","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"update_next = agent(rBirth ⋅ rPersist, Life(1); n=:Cell)\n\nview_sched(update_next)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The second for loop is overwriting curr with next for all cells","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"next_step = agent(compose(rClearCurr, rCopyNext, rClearNext), Life(1); n=:Cell)\n\nview_sched(next_step)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We then compose these together and wrap in an overall for loop with a counter.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"life(n::Int) = for_schedule(update_next ⋅ next_step, n) |> F\n\nconst L = life(1) # Game of life simulation that runs just one (global) timestep\n\nview_sched(L)","category":"page"},{"location":"generated/game_of_life/#Running-the-simulation","page":"Conway's Game of Life","title":"Running the simulation","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Make an initial state","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"G = make_grid([1 0 1 0 1; 0 1 0 1 0; 0 1 0 1 0; 1 0 1 0 1; 1 0 1 0 1])\n\nview_life_graph(G)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"(or, viewed in plaintext)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"view_life(G) |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Run the simulation","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"res = interpret(L, G; maxstep=1000);\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Look at the end state","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"res[end][1] |> codom |> view_life |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Visualize the results in the traj folder","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"view_traj(L, res[1:10], view_life; agent=true)","category":"page"},{"location":"api/#Library-Reference","page":"Library Reference","title":"Library Reference","text":"","category":"section"},{"location":"api/#Rewrite","page":"Library Reference","title":"Rewrite","text":"","category":"section"},{"location":"api/","page":"Library Reference","title":"Library Reference","text":"Modules = [\n AlgebraicRewriting.Constraints,\n AlgebraicRewriting.Utils,\n AlgebraicRewriting.DPO,\n AlgebraicRewriting.CoNeg,\n AlgebraicRewriting.SPO,\n AlgebraicRewriting.SqPO,\n AlgebraicRewriting.PBPO,\n AlgebraicRewriting.Migration\n]","category":"page"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate-Tuple{CGraph}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","text":"Apply migration to all literals in the constraint\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolAnd","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolAnd","text":"Conjunction of multiple expressions\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolConst","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolConst","text":"Constant, independent of context\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolExpr","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolExpr","text":"Something that, in a context, can be evaluated to a bool\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolNot","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolNot","text":"Negation of an expression\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolOr","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolOr","text":"Disjunction of multiple expressions\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.CGraph","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.CGraph","text":"\"nothing\" means something that will be determined via a quantifier Ints are explicit arguments provided when apply_constraint is called\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.Commutes","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.Commutes","text":"A commutative diagram with multiple parallel paths, asserted to either commute or to not commute\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.Constraint","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.Constraint","text":"A constraint graph and a BoolExpr (which refers to the constraint graph)\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.Quantifier","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.Quantifier","text":"Quantified edge\n\ne - which edge is filled in kind - Exists, Forall, or Exists! st - \"such that\", restrict the domain of quantification via a condition monic - restrict domain of quanitification to only monic matches\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.AppCond","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.AppCond","text":"Constraint a constraint that asserts (or denies) the existence of a triangle commuting.\n\n f₁\n\n(1) <- (2) ∃₂↘ ↓ λ₃ (3)\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.LiftCond-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.LiftCond","text":" ∀₂\n\n(1) → (3) ₁↓ ↗∃₃ ↓ λ₅ (2) → (4) ⁴\n\nTest a map (3)→(4), given maps (1)->(2)->(4). \n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.arity-Tuple{CGraph}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.arity","text":"Number of variables in a constraint graph\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.check_expr-Tuple{CGraph, Commutes}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.check_expr","text":"Validate a commutative diagram constraint makes sense\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.eval_boolexpr-Tuple{Commutes, CGraph, Vector{Union{Nothing, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.eval_boolexpr","text":"Check whether homs are equal by looping over domain.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.get_ob-Tuple{CGraph, Int64, Vector{Union{Nothing, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.get_ob","text":"Get the C-Set associated with a vertex in a CGraph\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.merge_graphs-Tuple{Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.merge_graphs","text":"Take two CGraphs and merge them along their overlapping vertices and edges Returns an ACSetColimit\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.Theories.:⊕-Tuple{Constraint, Constraint}","page":"Library Reference","title":"Catlab.Theories.:⊕","text":"Combine two constraints disjunctively, sharing as much of the computation graph as possible.\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.Theories.:⊗-Tuple{Constraint, Constraint}","page":"Library Reference","title":"Catlab.Theories.:⊗","text":"Combine two constraints conjunctively, sharing as much of the computation graph as possible (i.e. pushout along the maximum common subgraph)\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.Rule","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.Rule","text":"Rewrite rules which are (usually) encoded as spans. The L structure encodes a pattern to be matched. The R morphism encodes a replacement pattern to be substituted in. They are related to each other by an interface I with maps: L ⟵ I ⟶ R \n\nA semantics (DPO, SPO, CoNeg, or SqPO) must be chosen.\n\nControl the match-finding process by specifying whether the match is intended to be monic or not, as well as an optional application condition(s) \n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.can_match-Union{Tuple{T}, Tuple{Rule{T}, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.can_match","text":"Returns nothing if the match is acceptable for rewriting according to the rule, otherwise returns the reason why it should be rejected\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.freevars-Union{Tuple{T}, Tuple{Rule{T}, Symbol}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.freevars","text":"Get a list of AttrVar indices which are NOT bound by the I→R morphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map-Union{Tuple{T}, Tuple{Rule{T}, Any, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map","text":"Don't bind variables for things that are not ACSets\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map-Union{Tuple{T}, Tuple{Rule{T}, Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map","text":"Given the match morphism and the result, construct a map X → X′ which binds any free variables introduced into the result.\n\nL <- I -> R m ↓ ↓ ↓ res G <- • -> X ↓ X′\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_match-Tuple","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_match","text":"Get one match (if any exist) otherwise return \n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_matches-Union{Tuple{T}, Tuple{Rule{T}, ACSets.ACSetInterface.ACSet}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_matches","text":"Get list of possible matches based on the constraints of the rule\n\nThis function has the same behavior as the generic get_matches, but it is more performant because we do not have to query all homomorphisms before finding a valid match, in case n=1. \n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_matches-Union{Tuple{T}, Tuple{Rule{T}, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_matches","text":"If not rewriting ACSets, we have to compute entire Hom(L,G).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_pmap-Tuple{Symbol, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_pmap","text":"Extract the partial map (derived rule) from full output data\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_rmap-Tuple{Symbol, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_rmap","text":"Extract the map from the R to the result from the full output data\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite-Tuple{AlgebraicRewriting.Rewrite.Utils.AbsRule, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite","text":"rewrite(r::Rule, G; kw...)\n\nPerform a rewrite (automatically finding an arbitrary match) and return result.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match-Tuple{AlgebraicRewriting.Rewrite.Utils.AbsRule, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match","text":"rewrite_match(r::Rule, m; kw...)\n\nPerform a rewrite (with a supplied match morphism) and return result.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs-Tuple{Rule{:DPO}, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs","text":"Further induced equations between AttrVars, given a specific match morphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs-Tuple{Rule{:DPO}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs","text":"Ignore for other categories\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs-Tuple{Rule{:DPO}, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs","text":"A match may be invalid because two variables (which are to be assigned different values via the I -> R map) are identified (due to merging via the I->L map, which morally ought be monic but is not for AttrVars). We can check this before computing the pushout to make sure that we will not get an inconsistent result when trying to compute it. This requires executing the custom exprs of the rewrite rule, so we may wish to build in the ability to skip this step if that is computationally intensive.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{Rule{:DPO}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":"rewrite_match_maps(r::Rule{:DPO}, m)\n\nApply a DPO rewrite rule (given as a span, L<-I->R) to a ACSet using a match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H\n\nThis works for any type that implements pushout_complement and pushout\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{Rule{:CoNeg}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":"rewrite_match_maps(r::Rule{:CoNeg}, m)\n\nApply a CoNegation rewrite rule (given as a span, L↩I->R) to a ACSet using a monic match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H where K = ~L ∨ I\n\nThis works for any type that implements bi-Heyting logic operators ~ and ∨.\n\nThis is described here. Essentially, it is partway between DPO and SPO. Suppose the rule tries to delete two things, one of which satisfies the dangling condition, the other violates it. While DPO would fail to apply at all, and SPO would delete both things (cascading the deletion for the latter), co-negation rewriting would simply delete the item which can be deleted without cascading and ignore the other element.\n\nIt includes a quote which indicates that this method should work even when the match morphism isn't monic, if it satisfies the identification condition. Supporting this is not yet implemented.\n\nMatch morphisms which bind attribute variables are not monic, hence we this form of rewriting doesn't support VarACSets. Intuitively, it feels like this restriction could be relaxed.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.SPO.partial_pushout-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.SPO.partial_pushout","text":"C ← Ag ↪ A ↩ Af → B \n\nA ↩ f∇g → Bgf ↪ B ↓ ⌜ ↓ C ↩ Cfg -> D\n\nImplementation of Construction 6 in Löwe's \"Algebraic approach to SPO graph transformation\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.SqPO.final_pullback_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{Ob, Hom} where {Ob, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.SqPO.final_pullback_complement","text":"See Theorem 2 of 'Concurrency Theorems for Non-linear Rewriting Theories' f B <–- A m ↓ ↓ n C <– D g\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{Rule{:SqPO}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":"rewrite_match_maps(r::Rule{:SqPO},m; pres::Union{Nothing, Presentation}=nothing)\n\nSesqui-pushout is just like DPO, except we use a final pullback complement instead of a pushout complement.\n\nr.L r.R\n\nL <-⌞K -> R m ↓ ↓k ↓ r I <- • ->⌜O i o\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.PBPO.PBPORule","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.PBPO.PBPORule","text":" l r\n\nL ⟵ K ⟶ R tl ↓ ↓ tk <== tl, tk must be monic L' ⟵ K'\n\nIt is assumed we never want the typing/adherence match to be monic, but we can optionally restrict the match L → G to be monic.\n\nWe can attach application conditions to both the match morphism as well as the adherence morphism. Until morphism search under constraints becomes efficient, it's sometimes needed to just directly state the adherence morphism as a function of the match morphism.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.PBPO.canon-NTuple{5, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.PBPO.canon","text":"Take a PBPO rule and put into normal form, i.e. where the lower square forms a pullback\n\nSee Prop 2.4 of \"The PBPO graph transformation approach\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.PBPO.partial_abstract-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.PBPO.partial_abstract","text":"This construction addresses the following problem: ideally when we 'abstract' an ACSet from X to A->X, maps into X, say B->X, can be canonically pulled back to maps B->A which commute. However, A won't do here, because there may not even exist any maps B->A. If B has concrete attributes, then those cannot be sent to an AttrVar in A. Furthermore, if B has multiple 'references' to an AttrVar (two different edges, each with AttrVar(1), sent to two different edges with the same atttribute value in X), then there is no longer a canonical place to send AttrVar(1) to in A, as there is a distinct AttrVar for every single part+attr in X. So we need a construction which does two things to A->X, starting with a map B->X. 1.) replaces exactly the variables we need with concrete values in order to allow a map B->A, 2.) quotients variables in A so that there is exactly one choice for where to send attrvars in B such that the triangle commutes.\n\nStarting with a map L -> G (where G has no AttrVars), we want the analogous map into a \"partially abstracted\" version of G that has concrete attributes replaced with AttrVars EXCEPT for those attributes which are mapped to by concrete attributes of L. Likewise, multiple occurences of the same variable in L correspond to AttrVars which should be merged in the partially-abstracted G.\n\nFor example, for a schema with a single Ob and Attr (where all combinatorial maps are just {1↦1, 2↦2}):\n\nL = [AttrVar(1), :foo]\nG = [:bar, :foo, :baz]\nabs(G) = [AttrVar(1), AttrVar(2), AttrVar(3)]\nexpected result: [AttrVar(1), :foo, AttrVar(2)]\nL -> Partial_abs(G) ↓ ↑ G <- abs(G)\n\nThis function computes the top arrow of this diagram starting with the left arrow. The bottom arrow is computed by abstract_attributes and the right arrow by sub_vars. Furthermore, a map from Partial_abs(G) to G is provided.\n\nThis is the factorization system arising from a coreflective subcategory.\n\n(see https://ncatlab.org/nlab/show/reflective+factorization+system and https://blog.algebraicjulia.org/post/2023/06/varacsets/)\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map-Tuple{PBPORule, Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map","text":"Use exprs and k_exprs to fill in variables introduced by applying the rw rule.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_matches-Tuple{PBPORule, ACSets.ACSetInterface.ACSet}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_matches","text":"PBPO matches consist of two morphisms. First, a match m: L → G, and secondly a typing G → L′. With attributes, it is not so simple because G has concrete values for attributes and L′ may have variables. Therefore, we actually change the typing to map out of A, an abstracted version of G (with its attributes replaced by variables). So we lift matches L->G to matches L->A, then search α∈Hom(A,L′).\n\nIn general, we want α to be uniquely determined by m, so by default α_unique is set to true.\n\n m\n\nL⌟ ⟶ G || ↓ α L ⟶ L′ tl\n\n m\n\nL ⟶ G tl ↓ ↘a ↑ (abs = partial abstraction. Note a is Labs in the code.) L′⟵ A α\n\nThe \"strong match\" condition we enforce is that: tl⁻¹(α(A)) = a⁻¹(A). This means we can deduce precisely what m is by looking at α.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{PBPORule, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":" r\n K ----> R\ngₗ u ↓ gᵣ ⌜ ↓ w\n\nGₗ <–– Gk ––> Gᵣ α ↓ ⌞ ↓ u' L′ <– K′ tₗ\n\nFor the adherence morphism α to be valid, it must satisfy a condition with m, tₗ. This is checked for matches provided by get_matches, so by default we do not check it.\n\nL <–⌞• m ↓ ↓ G ⟵ Gk\n\nSee Lemma 7.2 of \"TERMINATION OF GRAPH TRANSFORMATION SYSTEMS USING WEIGHTED SUBGRAPH COUNTING\" by Overbeek and Endrullis (2023)\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Migration.pres_hash-Tuple{GATlab.Models.Presentations.Presentation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Migration.pres_hash","text":"Want a filename that is stable to multiple Julia sessions but changes when the schema changes. This minimizes the need to clear the cache.\n\n\n\n\n\n","category":"method"},{"location":"api/#Schedules","page":"Library Reference","title":"Schedules","text":"","category":"section"},{"location":"api/","page":"Library Reference","title":"Library Reference","text":"Modules = [\n AlgebraicRewriting.Theories,\n AlgebraicRewriting.Poly,\n AlgebraicRewriting.Wiring,\n AlgebraicRewriting.Eval,\n AlgebraicRewriting.Basic,\n AlgebraicRewriting.Conditionals,\n AlgebraicRewriting.RuleApps,\n AlgebraicRewriting.Queries,\n AlgebraicRewriting.Visuals\n]","category":"page"},{"location":"api/#AlgebraicRewriting.Schedules.Poly","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly","text":"Mealy machines (augmented with monadic output) are a user-friendly format for specifying a behavior tree. Behavior trees in general are not finitely expressible, but we focus on trees which can be lazily generated by functions.\n\nAlthough it is conceptually simple to think of a single set of \"input doors\" out \"output doors\" to enter/leave the Mealy machine, such that a Mealy machine has type A → B, we use Σᵢ Aᵢ → Σⱼ Bⱼ, where Aᵢ and Bⱼ are Julia types. This allows us to represent a Mealy machine with (Int + String)-many input doors, for example.\n\n\n\n\n\n","category":"module"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.List","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.List","text":"\"The list monad returns the set of packages labeled with a natural number N, each of which has N-many slots.\"\n\n\n\n\n\n","category":"constant"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.Maybe","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.Maybe","text":"\"The Maybe monad, y+1, consists of two packages, one with one slot and the other with no slots.\"\n\n\n\n\n\n","category":"constant"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.BTree","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.BTree","text":"Lazily grown behavior tree induced by a Mealy machine. The future behavior is dictated by the inputs seen thus far (i.e. a vector of WireVals).\n\nEach vertex is identified by a sequence of inputs and has a state of the Mealy machine associated with it.\n\nEach nonempty sequence of inputs has a MealyRes associated with it.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.BTree-Tuple{Vector{WireVal}}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.BTree","text":"Grow a tree and return the result.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.Mealy","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.Mealy","text":"A function that maintains a state (initially s0) and has monadic output for some polynomial monad t.\n\nThe function f must be of type S × WireVal → S × (t ◁ WireVal) \n\n (i.e. S × Wireval → MealyRes)\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.MealyRes","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.MealyRes","text":"Output of a Mealy machine\n\nnewS - The new state of the Mealy machine mval - outputs along with their monadic values (e.g. probability weights) msg - A message reporting something about the computation \n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.PMonad","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.PMonad","text":"Quotes in this docstring and others taken from David Spivak: https://topos.site/blog/2023/09/powers-of-polynomial-monads/#exponentiating-monads\n\n\"A polynomial monad is a polynomial functor t with coherent maps η: y → t and μ: t ◁ t → t.\n\nPolynomial monads can be thought of as offering compositional (possibly labeled) packages with some number of slots. The compositionality of this packaging says that (via the monad unit) we know how to package up a given element of any set, and that (via the monad multiplication) we can take a package of packages and simplify it to a single package.\"\n\nWe consider monads t of the form: t = Σ_{i ∈ t(1)} y^{t[i]}\n\nI is the type of labels, e.g. probability weights.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.Simulator","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.Simulator","text":"Equips a wiring diagram description of a simulator with mutable data structures (now behavior trees for each box, but possibly incremental homomorphism caches in the future). Requires that all the boxes of the WiringDiagram be convertable to BTrees.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.TrajStep","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.TrajStep","text":"A trajectory step is a box being fed a particular value\n\nThis only makes sense with reference to a WiringDiagram which box refers to.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.WireVal","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.WireVal","text":"For an in/output, Σᵢ Aᵢ, provide wire index + value on wire\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.add_edge-Union{Tuple{I}, Tuple{Traj{I}, TrajStep{I}}} where I","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.add_edge","text":"Append without mutating\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.apply_schedule-Union{Tuple{I}, Tuple{Simulator, Any}, Tuple{Simulator, Any, PMonad{I}}} where I","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.apply_schedule","text":"In theory applying a schedule should result in a list of ACSets associated with out ports and monad labels (e.g. probabilities), and if one were to want to recover the trajectory of the output one would have to use a Writer monad of some sort. For simplicity, the application of a schedule will simply return the trajectories themselves (monadic multiplication could in principle condense this output to the pure output).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.apply_traj_step-Tuple{Simulator, Traj, Catlab.WiringDiagrams.DirectedWiringDiagrams.Wire}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.apply_traj_step","text":"A particular trajectory enters a box. Out of the box comes a list of trajectories.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.curr_state-Tuple{Traj}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.curr_state","text":"Current state of the world\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.currwire-Tuple{Simulator, Traj}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.currwire","text":"Get the wire which the traj is currently on\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.joindist-Tuple{Any}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.joindist","text":"\"The lotteries monad returns the set of packages labeled with a lottery (a natural number N and a probability distribution on it) and again containing N-many slots.\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.joinstr-Tuple{Any}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.joinstr","text":"Writer monad\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate-Tuple{Schedule}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","text":"Map a functor over the data of a schedule\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.AgentBox","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.AgentBox","text":"Type for primitive boxes used in a schedule. These are the generating morphisms of a traced monoidal category, with objects being lists of ACSets.\n\n\n\n\n\n","category":"type"},{"location":"api/#ACSets.DenseACSets.sparsify-Tuple{Schedule}","page":"Library Reference","title":"ACSets.DenseACSets.sparsify","text":"Map sparisfication over the data of a schedule\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.merge_wires","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.merge_wires","text":"The comonoid structure - merging multiple wires into one. This is unproblematic because the world state only ever exists on one wire at a given time.\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.mk_sched-Union{Tuple{T}, Tuple{NamedTuple, NamedTuple, Names{T}, Union{AbstractDict, NamedTuple}, Expr}} where T","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.mk_sched","text":"Make a wiring diagram with ob/hom generators using @program macro\n\nTODO double check that this does not introduce any wire splitting.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.singleton-Tuple{AlgebraicRewriting.Schedules.Wiring.AgentBox}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.singleton","text":"Make a wiring diagram around a box\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.str_hom-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.str_hom","text":"Visualize the data of a CSet homomorphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.wire_vals-Tuple{Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagram, Int64}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.wire_vals","text":"1 = inwire, 2 = outwire\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Eval","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Eval","text":"Specialized code for handling rewriting of ACSets with the identity monad\n\n\n\n\n\n","category":"module"},{"location":"api/#AlgebraicRewriting.Schedules.Eval.interpret!-Tuple{Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagram, Catlab.CategoricalAlgebra.CSets.ACSetTransformation{<:ACSets.ACSetInterface.ACSet{<:ACSets.ACSetInterface.MarkAsDeleted}}}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Eval.interpret!","text":"interpret a wiring diagram, with each box updating its state in place\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Eval.interpret-Tuple{Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagram, Catlab.CategoricalAlgebra.CSets.ACSetTransformation{<:ACSets.ACSetInterface.ACSet{<:ACSets.ACSetInterface.MarkAsDeleted}}}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Eval.interpret","text":"Interpret a wiring diagram, recording the trajectory taken\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Basic.Initialize","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Basic.Initialize","text":"A box that spits out a constant ACSet with an empty agent above it. Possibly, it does not take any inputs, so it can act as a comonoid counit.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Basic.Strengthen","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Basic.Strengthen","text":"Adds to both agent and the state of the world via a pushout.\n\n Agent₁ → Agent₂\n ↓ ⇣ \n World₁ -->⌜World₂\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Basic.Weaken","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Basic.Weaken","text":"Change the agent to a subobject of the current agent without changing the world\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.Conditional","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.Conditional","text":"A primitive box in a NestedDWD which does not change the state but redirects it out of one of n wires. \n\nIt contains a function (A->X) -> ℝⁿ. This optionally depends on the internal state. This weights probability for n outports, conditional on the status of an ACSet. If the function just depends on X rather than the whole morphism, withagent is false. If the function does not depend on the internal state (assumed to be true iff initial state is nothing), then withstate is false.\n\nThe state and update function are by default trivial.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.const_cond-Tuple{Vector{Float64}, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.const_cond","text":"Create a branching point with fixed probabilities for each branch\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.for_schedule-Tuple{Schedule, Int64}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.for_schedule","text":"Perform a 1-1 schedule n times\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.if_cond-Tuple{Symbol, Function, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.if_cond","text":"Enter the 1st branch iff the world state evaluates to true\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.uniform-Tuple{Int64, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.uniform","text":"A uniform chance of leaving each of n branches\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.while_schedule-Tuple{Schedule, Function}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.while_schedule","text":"Perform a 1-1 schedule until a condition is met\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.RuleApps.RuleApp","page":"Library Reference","title":"AlgebraicRewriting.Schedules.RuleApps.RuleApp","text":"Has the semantics of applying the rule to some match that is found (no guarantees on which one, which should be controlled by application conditions). If rewrite occurs, exit mode 1, else exit mode 2.\n\nThe agent is related to the L and R patterns of the rule. This can be done via a Span, or implicitly as a homomorphism into \"I\" of the rewrite rule, and alternatively just from the shape of the agent alone (if it is identical to I, take the id map, otherwise take the unique morphism into I).\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.RuleApps.has_match-Tuple{String, AlgebraicRewriting.Rewrite.Utils.AbsRule, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.RuleApps.has_match","text":"A box that takes the first output iff there is a match from a rule into the current state\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.RuleApps.loop_rule-Tuple{RuleApp}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.RuleApps.loop_rule","text":"Feed the \"rewrite applied\" output back into the input of the rule application\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Queries.Query","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Queries.Query","text":"Has an A input/output and a B input/output (by default, the B input can be changed to some other type if needed). \n\nA R ---------↖\n↓ ↓ []\n\n⌜–––-⌝ [] | Query | [agent subroutine] ⌞–––-⌟ [] ↓ ↓ ↓ [] A B ∅ [] ↘–––––-↗ Performs one action per element of Hom(B,X), optionally with some constraints. (i.e. sends you out along the B wire with agent Bₙ->X). \n\nAfter you have done this for all Bₙ, then you exit the A port (you need to update the A->X map, and, if at any point the agent was deleted, then you exit a third door typed by 0).\n\nA constraint optionally will be applied to (1) the A->W<-B cospan of old agent and purported new agent. (the new agent is the first argument to the constraint) \n\n\n\n\n\n","category":"type"},{"location":"api/#CategoricalAlgebra","page":"Library Reference","title":"CategoricalAlgebra","text":"","category":"section"},{"location":"api/","page":"Library Reference","title":"Library Reference","text":"Modules = [\nAlgebraicRewriting.FinSets,\nAlgebraicRewriting.CSets,\nAlgebraicRewriting.StructuredCospans,\nAlgebraicRewriting.PartialMap\n]","category":"page"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.id_condition-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s1\", Hom} where {var\"#s1\"<:(Catlab.CategoricalAlgebra.FinSets.FinSet{Int64}), Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.id_condition","text":"Check identification condition for pushout complement of finite sets.\n\nThe identification condition says that the functions do not map (1) both a deleted item and a preserved item in L to the same item in G or (2) two distinct deleted items to the same item. It is trivially satisfied for injective functions.\n\nReturns pair of iterators of\n\n(1) a nondeleted item that maps to a deleted item in G (2) a pair of distinct items in L that are deleted yet mapped to the same item in G.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s3\", Hom} where {var\"#s3\"<:(Catlab.CategoricalAlgebra.FinSets.FinSet{Int64}), Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"Compute a pushout complement of finite sets, if possible.\n\nGiven functions l I L and m L G to form a pushout square\n\nl\n\nL ← I m ↓ ↓k G ← K g\n\ndefine the set K = G m(L l(I)) and take g K G to be the inclusion. Then the map k I K is determined by the map lm I G from the requirement that the square commutes.\n\nPushout complements exist only if the identification condition is satisfied. An error will be raised if the pushout complement cannot be constructed. To check this in advance, use can_pushout_complement.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","text":"TODO: check if functorial\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.cascade_subobj-Tuple{ACSets.ACSetInterface.ACSet, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.cascade_subobj","text":"Recursively delete anything, e.g. deleting a vertex deletes its edge\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.check_pb-NTuple{4, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.check_pb","text":"Y i↘ f_ X → • g_ ↓ ⌟ ↓ f • → • g\n\nCheck whether (X, f,g) is the pullback of (f,g), up to isomorphism (i.e. the pullback of f and g produces (Y,π₁,π₂), where Y is isomorphic to X and i⋅f_ = π₁ & i⋅g_ = π₂.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.fibers-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.fibers","text":"Every morphism induces a partition of the parts of the domain. This function finds every nontrivial partition (size greater than one element) for the objects of the schema.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.gluing_conditions-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s55\", Hom} where {var\"#s55\"<:ACSets.ACSetInterface.ACSet, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.gluing_conditions","text":"Check both id condition and dangling condition\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.invert_hom-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.invert_hom","text":"Invert a morphism which may not be monic nor epic. When the morphism is not monic, an arbitrary element of the preimage is mapped to. When it is not epic, a completely arbitrary element is mapped to.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.invert_iso","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.invert_iso","text":"Invert some (presumed iso) components of an ACSetTransformation (given by s)\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.sub_vars","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.sub_vars","text":"Given a value for each variable, create a morphism X → X′ which applies the substitution. We do this via pushout.\n\nO –> X where C has AttrVars for merge equivalence classes ↓ and O has only AttrVars (sent to concrete values or eq classes C in the map to C.\n\nsubs and merge are dictionaries keyed by attrtype names\n\nsubs values are int-keyed dictionaries indicating binding, e.g. ; subs = (Weight = Dict(1 => 3.20, 5 => 2.32), ...)\n\nmerge values are vectors of vectors indicating equivalence classes, e.g. ; merge = (Weight = [[2,3], [4,6]], ...)\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs","text":"Further induced equations between AttrVars, given a specific match morphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.var_pullback-Union{Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multicospan{var\"#s64\", Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {var\"#s64\"<:(ACSets.DenseACSets.StructACSet{S, Ts}), Hom}}, Tuple{Ts}, Tuple{S}} where {S, Ts}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.var_pullback","text":"Take an ACSet pullback combinatorially and freely add variables for all attribute subparts.\n\nThis relies on implementation details of abstract.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.can_pushout_complement-Tuple{Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.can_pushout_complement","text":"Can a pushout complement be constructed for a composable pair?\n\nEven in nice categories, this is not generally possible.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"Pushout complement: extend composable pair to a pushout square.\n\nPushout complements are the essential ingredient for double pushout (DPO) rewriting.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s56\", Hom} where {var\"#s56\"<:Catlab.CategoricalAlgebra.SliceCategories.Slice, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"pushout_complement(f::SliceHom, g::SliceHom)\n\nCompute a pushout complement in a slice category by using the pushout complement in the underlying category.\n\n f\n\nB <– A –-⌝ | ↘ ↙ | g| X | f′ ↓ ↗ ↖ cx | D <–- C <– g′\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s56\", var\"#s57\", <:StaticArraysCore.StaticArray{Tuple{2}, var\"#s57\", 1}} where {var\"#s56\"<:ACSets.ACSetInterface.ACSet, var\"#s57\"<:Catlab.CategoricalAlgebra.CSets.TightACSetTransformation}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"Compute pushout complement of attributed C-sets, if possible.\n\nThe pushout complement is constructed pointwise from pushout complements of finite sets. If any of the pointwise identification conditions fail (in FinSet), this method will raise an error. If the dangling condition fails, the resulting C-set will be only partially defined. To check all these conditions in advance, use the function can_pushout_complement.\n\nIn the absence of AttrVars, K is a subobject of G. But we want to be able to change the value of attributes. So any variables in I are not concretized by the I->K map. However, AttrVars may be merged together if m: L -> G merges parts together.\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.CategoricalAlgebra.HomSearch.homomorphisms-Tuple{Catlab.CategoricalAlgebra.SliceCategories.Slice, Catlab.CategoricalAlgebra.SliceCategories.Slice}","page":"Library Reference","title":"Catlab.CategoricalAlgebra.HomSearch.homomorphisms","text":"This could be made more efficient as a constraint during homomorphism finding.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.StructuredMultiCospanHom","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.StructuredMultiCospanHom","text":"A component-wise map between two cospans. The first component given is the apex map, with the following maps being the legs.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.openrule","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.openrule","text":"A span of StructuredMulticospanHoms, interpreted as a DPO rewrite rule\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_-Tuple{openrule, openrule}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_","text":"composeH_(r₁, r₂)\n\ncompose two rewrite rules horizontally (via pushouts) as shown below: L₁₋₍ₙ₋₁₎-> L <- Lₙ X₁ -> X <- X₂₋ₘ L₁₋₍ₙ₋₁₎ -> L +Lₙ X <- X₂₋ₘ ↑ λ ↑ ↑ ↑ ↑ χ ↑ ↑ ↑ ↑ I₁₋₍ₙ₋₁₎-> I <- Iₙ ∘h Y₁ -> Y <- Y₂₋ₘ = I₁₋₍ₙ₋₁₎ -> I +Iₙ Y <- Y₂₋ₘ ↓ ρ ↓ ↓ ↓ ↓ ζ ↓ ↓ ↓ ↓ R₁₋₍ₙ₋₁₎-> R <- Rₙ Z₁ -> Z <- Z₂₋ₘ R₁₋₍ₙ₋₁₎ -> R +Rₙ Z <- Z₂₋ₘ\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_-Union{Tuple{L}, Tuple{Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan{L}, Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan{L}}} where L","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_","text":"Cospan composition given by pushout\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_","text":"Finset span composition given by pullback\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_-Tuple{openrule, openrule}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_","text":"composeV_(r₁, r₂)\n\ncompose two rewrite rules vertically with pullbacks, as shown below: L₁₋ₙ -> L ↑ ↑ I₁₋ₙ -> I ↓ ↓ L₁₋ₙ -> L R₁₋ₙ -> R ↑ ↑ ∘v = I₁₋ₙ ×ᵣ₁₋ₙ Θ₁₋ₙ -> I ×ᵣ Θ Λ₁₋ₙ -> Λ ↓ ↓ ↑ ↑ Ω₁₋ₙ -> Ω Θ₁₋ₙ -> Θ ↓ ↓ Ω₁₋ₙ -> Ω\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.id2H_-Union{Tuple{L_}, Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanOb{L_}}} where L_","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.id2H_","text":"Pass dummy value in because a span of invertible FinFunctions does not retain L type\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.idV_-Union{Tuple{Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanOb{L}}, Tuple{L}} where L","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.idV_","text":"Vertical arrows are spans of invertible finfunctions\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_pushout_complement-Tuple{openrule, StructuredMultiCospanHom}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_pushout_complement","text":"Initial data: 4 structured cospans + 3 cospan morphisms: μ, λ, ρ g G₁₋ₙ –> G ↑ l ↑ μ L₁₋ₙ –> L ↑ i ↑ λ I₁₋ₙ –> I ↓ r ↓ ρ R₁₋ₙ –> R\n\nComputed data: 2 new structured cospans + 4 cospan morphisms: γ, η, ik, rh G₁₋ₙ G ↑ k ↑ γ ik I₁₋ₙ -> K₁₋ₙ –> K <– I ↓ h ↓ η rh R₁₋ₙ -> H₁₋ₙ –> H <– R In the context of the legs of a multicospan, the indices 1-n refer to the n legs of the cospan. In the context of a map of multicospans, there are 1-(n+1) maps, with the first one designating the map of the apexes. Hence it can make sense to have the elements: zip(legs, maps[2:end]) = [(legᵢ, mapᵢ), ...]\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite-Tuple{openrule, StructuredMulticospan}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite","text":"Apply a rewrite rule to a structured multicospan, where a matching cospan homomorphism is found automatically. If multiple matches are found, a particular one can be selected using m_index. Returns nothing if none are found.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite_match-Tuple{openrule, StructuredMultiCospanHom}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite_match","text":"Extract the rewritten structured cospan from the induced rewrite rule\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.CategoricalAlgebra.HomSearch.homomorphisms-Union{Tuple{L}, Tuple{StructuredMulticospan{L}, StructuredMulticospan{L}}} where L","page":"Library Reference","title":"Catlab.CategoricalAlgebra.HomSearch.homomorphisms","text":"Find homomorphisms between structured cospans. These are constrained to be iso on the legs of the cospans. Solving this w/ homomorphism finding requires a dynamic acset, and the current hack will be replaced once those are available.\n\nA homomorphism backend that uses SAT/SMT would also make this viable to do without hacking.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.check_eqs-Tuple{ACSets.DenseACSets.StructACSet, GATlab.Models.Presentations.Presentation, Symbol, Int64}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.check_eqs","text":"Confirm a C-Set satisfies its equational axioms\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.eval_path-Tuple{ACSets.DenseACSets.StructACSet, Any, Int64}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.eval_path","text":"Take a GATExpr (an id morphism, a generator, or a composite) and evaluate, starting at a particular point.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_eta-Tuple{ACSets.DenseACSets.StructCSet}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_eta","text":"The natural injection from X ⟶ T(X) When evaluated on the terminal object, this gives the subobject classfier.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_universal_property-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_universal_property","text":"A partial function is defined by the following span: m f A ↩ X → B\n\nWe compute ϕ(m,f): A ⟶ T(B) such that the following is a pullback square: f X ⟶ B m ↓ ↓ η(B) A ⟶ T(B) ϕ\n\nEssentially, ϕ sends elements of A to the 'real' values in T(B) when A is in the subobject picked out by X. When A is 'deleted', it picks out the right element of the additional data added by T(B).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_hom-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_hom","text":"Because the functorial embedding of objects keeps a copy of the original data, what to do with morphisms is just carry them along. Because our implementation adds all of the additional stuff afterwards, index-wise, we can use literally the same data for a morphism lifted from X⟶Y to T(X)⟶T(Y).\n\nHowever, we still need to map the extra stuff in T(X) to the proper extra stuff in T(Y).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_ob-Tuple{ACSets.DenseACSets.StructCSet}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_ob","text":"A functor T, playing the role of Maybe in Set, but generalized to C-Sets.\n\nWhen called on the terminal object, this produces the subobject classifier: See Mulry \"Partial map classifiers and cartesian closed categories\" (1994)\n\nThis function specifies what T does on objects. The key properties:\n\nfor all X ∈ Ob(C), η(X):X⟶T(X) is monic. m f ϕ(m,f)\nfor each span A ↩ X → B, there exists a unique morphism A ⟶ T(B) such that (m,f) is the pullback of ϕ(m,f),η(B))\n\nNot only do we add an extra element to each component of the C-Set, but we need to consider the possibility that a component (with n outgoing morphisms) has any combination of the targets of those morphisms deleted (like the subobject classifier, there are different ways for something to be deleted).\n\nFor example, in Graph, an edge can be deleted that goes between any two vertices of the graph. We can't map all deleted edges to the same point in T(E) (if we're going to satisfy that desired property #2), so we need an extra edge in T(E) for every possibility (from V1 to V2, from V1 to V3, ..., from [Deleted] to V1, ..., from V2 to [Deleted], ... from [Deleted] to [Deleted]), where [Deleted] is our name for the extra element added to T(V).\n\n [src] [tgt]\n\nThus, T(E) ≅ |E| + (|V|+1) × (|V|+1).\n\nIn general, T(X) ≅ |X| + ∏ₕ(|T(codom(h))|) for each outgoing morphism h::X⟶Y\n\nthe |X| corresponds to the 'real' elements of X\nthe second term corresponds to the possible ways an X can be deleted.\nThis recursive formula means we require the schema of the C-set to be acyclic otherwise the size is infinite (assumes schema is free).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.topo_obs-Tuple{Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.topo_obs","text":"Get topological sort of objects of a schema. Fail if cyclic.\n\n\n\n\n\n","category":"method"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"EditURL = \"../../literate/lotka_volterra.jl\"","category":"page"},{"location":"generated/lotka_volterra/#Lotka-Volterra","page":"Lotka Volterra","title":"Lotka Volterra","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"This is a demonstration of a predator-prey agent-based model.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We start with importing some libraries.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"using Catlab, DataMigrations, AlgebraicRewriting\nusing Random, Test\nusing Luxor # optional: makes the sequence of images via `view_traj` at the end\n\nusing Catlab.Graphics.Graphviz: Attributes, Statement, Node\nusing Catlab.Graphics.Graphviz\n\nconst hom = homomorphism\n\nRandom.seed!(123);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Ontology","page":"Lotka Volterra","title":"Ontology","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Defining an ontology is stating what data is required to specify a state of the simulation at some point in time. In AlgebraicJulia, this is done via declaring a Presentation, i.e. a database schema. Objects (Ob, or tables) are types of entities. Homs (Hom, or foreign keys) are functional relationships between the aforementioned entities. AttrTypes are placeholders for Julia types, which are assigned to Ob via attributes (Attr).","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"The schema below extends the schema for directed graphs, which consists in two tables (E and V, for edges and vertices) and two homs (src and tgt, E→V). It says there are two more types of entities, Sheep and Wolf, and they can be thought of as living on the graph due to homs sheep_loc and wolf_loc which assign each of them a vertex.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Furthermore, we want to give these entities some attributes. In this model, wolves and sheep both have \"energy\", given by Eng (a type variable, which we'll later instantiate with Int). Also, grass lives on vertices, and it's represented by an integer. countdown being zero means the grass is ready to eat, whereas a value above zero represents a counter of time the grass needs until it grows back.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"There is also a direction attribute type, and the edges (as well as animals) will be oriented in a particular direction at any point in time.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"@present SchLV <: SchGraph begin\n (Sheep, Wolf)::Ob\n sheep_loc::Hom(Sheep, V); wolf_loc::Hom(Wolf, V)\n\n (Time, Eng)::AttrType\n countdown::Attr(V, Time);\n sheep_eng::Attr(Sheep, Eng); wolf_eng::Attr(Wolf, Eng)\n\n Dir::AttrType\n dir::Attr(E, Dir); sheep_dir::Attr(Sheep, Dir); wolf_dir::Attr(Wolf, Dir)\nend\n\n# efficient ABM rewriting uses BitSetParts rather than DenseParts to allow\n# in-place pushout rewriting, rather than pure/non-mutating pushouts.)\n@acset_type LV_Generic(SchLV, part_type=BitSetParts) <: HasGraph\nconst LV = LV_Generic{Int, Int, Symbol}\n\nto_graphviz(SchLV; prog=\"dot\")","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We can further extend this schema with an additional attribute of (x,y) coordinates for every vertex. This is nice for visualization but is otherwise unnecessary when doing the actual agent-based modeling. So what we will do is build our model with the LV schema and then run our model with the LV′ schema.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"@present SchLV′ <: SchLV begin\n Coord::AttrType\n coord::Attr(V, Coord)\nend\n\n@acset_type LV′_Generic(SchLV′, part_type=BitSetParts) <: HasGraph\nconst LV′ = LV′_Generic{Int, Int, Symbol, Tuple{Int,Int}};\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We will be representing directions as Symbols and encode the geometry via left and right functions. The attribute will only take values :N, :E, :W, or :S.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"import Catlab.CategoricalAlgebra: left, right\n\nfunction right(s::Symbol)\n if s == :N\n return :E\n elseif s == :S\n return :W\n elseif s == :E\n return :S\n elseif s == :W\n return :N\n end\nend\n\nfunction left(s::Symbol)\n if s == :N\n return :W\n elseif s == :S\n return :E\n elseif s == :E\n return :N\n elseif s == :W\n return :S\n end\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Data-migration-functors","page":"Lotka Volterra","title":"Data migration functors","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"The schema LV has a certain symmetry between wolves and sheep, and this symmetry can be used to take instances of the schema (i.e. world states) and swap the wolves and the sheep. This is helpful for avoiding repeating work: there are certain actions that wolves and sheep share, so, by using this data migration, we can define them in terms of sheep and then migrate along F to obtain the analogous actions for wolves.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"F = Migrate(\n Dict(:Sheep => :Wolf, :Wolf => :Sheep),\n Dict([:sheep_loc => :wolf_loc, :wolf_loc => :sheep_loc,\n :sheep_eng => :wolf_eng, :wolf_eng => :sheep_eng, :countdown => :countdown,\n :sheep_dir => :wolf_dir, :wolf_dir => :sheep_dir,]), SchLV, LV);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We ought to be able to take a state of the world (with no coordinate information) and obtain a state of the world with coordinates (the canonical way to do this is to assign \"variables\" for the values of the coordinates).","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"F2 = Migrate(SchLV, LV, SchLV′, LV′; delta=false);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Initializing-and-visualizing-world-states","page":"Lotka Volterra","title":"Initializing and visualizing world states","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"To help us create initial states for simulations, here is a helper function that makes an n × n grid with periodic boundary conditions. Edges in each cardinal direction originate at every point.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"function create_grid(n::Int)\n lv = LV′()\n coords = Dict()\n for i in 0:n-1 # Initialize grass 50% green, 50% uniformly between 0-30\n for j in 0:n-1\n coords[i=>j] = add_part!(lv, :V; countdown=max(0, rand(-30:30)), coord=(i, j))\n end\n end\n for i in 0:n-1\n for j in 0:n-1\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[mod(i + 1, n)=>j], dir=:E)\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[mod(i - 1, n)=>j], dir=:W)\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[i=>mod(j + 1, n)], dir=:N)\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[i=>mod(j - 1, n)], dir=:S)\n end\n end\n lv\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"To initialize a state of the world with sheep and wolves, we also accept parameters which indicate the fraction of spaces that are populated with that animal.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"function initialize(n::Int, sheep::Float64, wolves::Float64)::LV′\n grid = create_grid(n)\n args = [(sheep, :Sheep, :sheep_loc, :sheep_eng, :sheep_dir),\n (wolves, :Wolf, :wolf_loc, :wolf_eng, :wolf_dir)]\n for (n_, name, loc, eng, d) in args\n for _ in 1:round(Int, n_ * n^2)\n dic = Dict([eng => 5, loc => rand(vertices(grid)),\n d => rand([:N, :E, :S, :W])])\n add_part!(grid, name; dic...)\n end\n end\n grid\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Some visualization code below will allow us to see states of the world. Edges are left implicit (we know from how the graphs were constructed that there are edges between every pair of adjacent vertices).","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"supscript_d = Dict(['1' => '¹', '2' => '²', '3' => '³', '4' => '⁴', '5' => '⁵', '6' => '⁶', '7' => '⁷', '8' => '⁸', '9' => '⁹', '0' => '⁰', 'x' => 'ˣ', 'y' => 'ʸ', 'z' => 'ᶻ', 'a' => 'ᵃ', 'b' => 'ᵇ', 'c' => 'ᶜ', 'd' => 'ᵈ'])\nsupscript(x::String) = join([get(supscript_d, c, c) for c in x]); # energy shown in superscript\n\nfunction view_LV(p::ACSetTransformation, pth=tempname(); name=\"G\", title=\"\")\n if nparts(dom(p), :Wolf) == 1\n star = :Wolf => p[:Wolf](1)\n elseif nparts(dom(p), :Sheep) == 1\n star = :Sheep => p[:Sheep](1)\n elseif nparts(dom(p), :V) == 1\n star = :V => p[:V](1)\n else\n star = nothing\n end\n view_LV(codom(p), pth; name=name, title=title, star=star)\nend\n\nfunction view_LV(p::LV′, pth=tempname(); name=\"G\", title=\"\", star=nothing)\n pstr = [\"$(i),$(j)!\" for (i, j) in p[:coord]]\n stmts = Statement[]\n for s in 1:nv(p)\n st = (star == (:V => s)) ? \"*\" : \"\"\n gv = p[s, :countdown]\n col = gv == 0 ? \"lightgreen\" : \"tan\"\n push!(stmts, Node(\"v$s\", Attributes(\n :label => gv == 0 ? \"\" : string(gv) * st,\n :shape => \"circle\",\n :color => col, :pos => pstr[s])))\n end\n d = Dict([:E => (1, 0), :N => (0, 1), :S => (0, -1), :W => (-1, 0),])\n\n args = [(:true, :Wolf, :wolf_loc, :wolf_eng, :wolf_dir),\n (false, :Sheep, :sheep_loc, :sheep_eng, :sheep_dir)]\n\n for (is_wolf, prt, loc, eng, dr) in args\n for w in parts(p, prt)\n st = (star == ((is_wolf ? :Wolf : :Sheep) => w)) ? \"*\" : \"\"\n e = only(incident(p, p[w, loc], :src) ∩ incident(p, p[w, dr], :dir))\n s = src(p, e)\n dx, dy = d[p[e, :dir]]\n (sx, sy) = p[s, :coord]\n\n L, R = 0.25, 0.1\n wx = sx + L * dx + R * rand()\n wy = sy + L * dy + R * rand()\n ID = \"$(is_wolf ? :w : :s)$w\"\n append!(stmts, [Node(ID, Attributes(\n :label => \"$w\" * supscript(\"$(p[w,eng])\") * st,\n :shape => \"square\", :width => \"0.3px\", :height => \"0.3px\", :fixedsize => \"true\",\n :pos => \"$(wx),$(wy)!\", :color => is_wolf ? \"red\" : \"lightblue\"))])\n end\n end\n\n g = Graphviz.Digraph(name, Statement[stmts...]; prog=\"neato\",\n graph_attrs=Attributes(:label => title, :labelloc => \"t\"),\n node_attrs=Attributes(:shape => \"plain\", :style => \"filled\"))\n open(pth, \"w\") do io\n show(io, \"image/svg+xml\", g)\n end\n g\nend\n\ninit = initialize(2, 0.5, 0.5)\nview_LV(init)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Not only can we visualize states of the world, but we can visualize certain states of the world with certain distinguished agents, such as a sheep, wolf, or patch of grass. The way we specify a state of the world (X) with a distinguished sheep (for example) is a morphism S → X, where S is an ACSet with a single sheep in it.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Below we manually construct a generic sheep (in LV, which doesn't have coordinates). We then use the data migration to give it generic coordinates to obtain a generic LV′ sheep. We use this as the domain of a hom that assigns the sheep to Sheep #2 of the world state init from above.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"S = @acset LV begin V=1; Sheep=1; Dir=1; Eng=1; Time=1;\n sheep_loc=1; sheep_dir=[AttrVar(1)]; sheep_eng=[AttrVar(1)]; countdown=[AttrVar(1)]\nend\n\nview_LV(hom(F2(S), init; initial=(Sheep=[2],)))","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"It will be helpful to not have to manually construct \"generic\" world states like above because it's tedious. We want to say \"give me a sheep\" or \"give me a sheep and a wolf that are on the same vertex\" and have it automatically specify the remaining information in the most generic way possible. The @acset_colim macro is perfect for exactly this. In order to use that macro, we need to compute something first with the yoneda_cache function.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"yLV = yoneda_cache(LV; clear=false); # cache=false means reuse cached results\nI = LV() # Empty agent type\nS = @acset_colim yLV begin s::Sheep end # Generic sheep agent\nW = F(S) # Generic wolf agent, obtained via the swapping `F` data migration\nG = @acset_colim yLV begin v::V end # Generic grass agent\nN = Names(Dict(\"W\" => W, \"S\" => S, \"G\" => G, \"\" => I)); # give these ACSets names\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Rules","page":"Lotka Volterra","title":"Rules","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We have finished specifying what makes up a simulation state, and next is to define what sorts of transitions are possible. This is done by declaring rewrite rules. We also will put these rules into little boxes with an incoming wire and two outgoing wires (called a RuleApp), where wires correspond to the successful (resp. unsuccessful) application of the rewrite rule. In the next section we will focus on assembling these miniature wiring diagrams into an overall simulation.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Here we just note that the wires of the simulation must be labeled with an agent. This is because, at all points in time, there is a distinguished agent (i.e. a morphism A → X, where A is an ACSet with a generic something in it, e.g. a generic sheep like above). So when we wrap our rules into the RuleApp boxes, we need to also specify what those distinguished agents are and how they relate to the pattern + replacement of the rewrite rule within the box.","category":"page"},{"location":"generated/lotka_volterra/#Rotating","page":"Lotka Volterra","title":"Rotating","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Our first action that is possible for sheep (and wolves) is rotation. Animals will, with some probability, change their orientation. This is a rewrite rule which only modifies an attribute rather than changing any combinatorial data, so rather than the usual span L ← I → R data required we simply put in a single ACSet along with an expr dictionary which states how attributes change.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"rl = Rule(S; expr=(Dir=[xs -> left(only(xs))],));\nrr = Rule(S; expr=(Dir=[xs -> right(only(xs))],));\n\nsheep_rotate_l = tryrule(RuleApp(:turn_left, rl, S));\nsheep_rotate_r = tryrule(RuleApp(:turn_right, rr, S));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We can imagine executing these rules in sequence","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"seq_sched = (sheep_rotate_l ⋅ sheep_rotate_r);\nview_sched(seq_sched; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"... or in parallel.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"par_sched = (sheep_rotate_l ⊗ sheep_rotate_r);\nview_sched(par_sched; names=N)","category":"page"},{"location":"generated/lotka_volterra/#Test-rotation","page":"Lotka Volterra","title":"Test rotation","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n E=1; Sheep=1; V=2\n src=1; tgt=2; dir=:W; countdown = [0, 0]\n sheep_loc=1; sheep_eng=100; sheep_dir=:N\n end;\n\n expected = copy(ex);\n expected[:sheep_dir] = :W\n @test is_isomorphic(rewrite(rl, ex), expected)\n rewrite!(rl, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Moving-forward","page":"Lotka Volterra","title":"Moving forward","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_fwd_l = @acset_colim yLV begin\n e::E; s::Sheep;\n sheep_loc(s) == src(e);\n dir(e) == sheep_dir(s)\nend\n\ns_fwd_i = @acset_colim yLV begin e::E end\n\ns_fwd_r = @acset_colim yLV begin\n e::E; s::Sheep; sheep_loc(s) == tgt(e); dir(e) == sheep_dir(s)\nend;\n\ns_n = @acset_colim yLV begin\n e::E; s::Sheep;\n sheep_loc(s) == src(e); dir(e) == sheep_dir(s)\n sheep_eng(s) == 0\nend;\n\nsheep_fwd_rule = Rule(\n hom(s_fwd_i, s_fwd_l; monic=true),\n hom(s_fwd_i, s_fwd_r; monic=true),\n ac=[AppCond(hom(s_fwd_l, s_n), false)],\n expr=(Eng=[vs -> only(vs) - 1],))\n;\n\nsheep_fwd = tryrule(RuleApp(:move_fwd, sheep_fwd_rule,\n hom(S, s_fwd_l), hom(S, s_fwd_r)));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Moving-forward-test","page":"Lotka Volterra","title":"Moving forward test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n V=3; E=2; Sheep=1;\n countdown=[0,0,0]\n src=[1,2]; tgt=[2,3]; dir=[:N,:W]\n sheep_loc=1; sheep_dir=:N; sheep_eng = 10\n end\n expected = copy(ex);\n expected[:sheep_loc] = 2\n expected[:sheep_eng] = 9\n @test is_isomorphic(expected, rewrite(sheep_fwd_rule, ex))\n rewrite!(sheep_fwd_rule, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-eat-grass","page":"Lotka Volterra","title":"Sheep eat grass","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_eat_pac = @acset_colim yLV begin s::Sheep; countdown(sheep_loc(s)) == 0 end;\n\nse_rule = Rule(S; expr=(Eng=[vs -> only(vs) + 4], Time=[vs -> 30],),\n ac=[AppCond(hom(S, s_eat_pac))]);\n\nsheep_eat = tryrule(RuleApp(:Sheep_eat, se_rule, S));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-eating-test","page":"Lotka Volterra","title":"Sheep eating test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n E=1; V=2; Sheep=1;\n src=1; tgt=2; dir=:S; countdown=[10, 0]\n sheep_loc = 2; sheep_eng = 3; sheep_dir=:W\n end\n\n expected = copy(ex)\n expected[2,:countdown] = 30\n expected[1,:sheep_eng] = 7\n\n @test is_isomorphic(expected, rewrite(se_rule, ex))\n rewrite!(se_rule, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Wolves-eat-sheep","page":"Lotka Volterra","title":"Wolves eat sheep","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"w_eat_l = @acset_colim yLV begin\n s::Sheep; w::Wolf\n sheep_loc(s) == wolf_loc(w)\nend;\n\nwe_rule = Rule(hom(W, w_eat_l), id(W); expr=(Eng=[vs -> vs[2] + 20],));\n\nwolf_eat = tryrule(RuleApp(:Wolf_eat, we_rule, W));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Wolf-eating-test","page":"Lotka Volterra","title":"Wolf eating test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n Sheep=1; Wolf=1; V=3; E=2;\n src=[1,2]; tgt=[2,3]; countdown=[9,10,11]; dir=[:N,:N];\n sheep_loc=2; sheep_eng=[3]; sheep_dir=[:N]\n wolf_loc=[2]; wolf_eng=[16]; wolf_dir=[:S]\n end\n\n expected = copy(ex)\n expected[1, :wolf_eng] = 36\n rem_part!(expected, :Sheep, 1)\n\n @test is_isomorphic(rewrite(we_rule,ex), expected)\n rewrite!(we_rule, ex)\n @test is_isomorphic(ex,expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-starvation","page":"Lotka Volterra","title":"Sheep starvation","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_die_l = @acset_colim yLV begin s::Sheep; sheep_eng(s) == 0 end;\n\nsheep_die_rule = Rule(hom(G, s_die_l), id(G))\nsheep_starve = (RuleApp(:starve, sheep_die_rule,\n hom(S, s_die_l), create(G))\n ⋅\n (id([I]) ⊗ Weaken(create(S))) ⋅ merge_wires(I));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-starvation-test","page":"Lotka Volterra","title":"Sheep starvation test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n V=1; Sheep=1; Wolf=1\n countdown=20;\n sheep_loc=1; sheep_eng=0; sheep_dir=:W\n wolf_loc=1; wolf_eng=10; wolf_dir=:S\n end\n expected = copy(ex)\n rem_part!(expected, :Sheep, 1)\n\n @test is_isomorphic(rewrite(sheep_die_rule,ex), expected)\n rewrite!(sheep_die_rule,ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Reproduction","page":"Lotka Volterra","title":"Reproduction","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_reprod_r = @acset_colim yLV begin\n (x, y)::Sheep\n sheep_loc(x) == sheep_loc(y)\nend;\n\nsheep_reprod_rule = Rule(\n hom(G, S),\n hom(G, s_reprod_r);\n expr=(Dir=fill(vs->only(vs) ,2),\n Eng=fill(vs -> round(Int, vs[1] / 2, RoundUp), 2),)\n);\n\nsheep_reprod = RuleApp(:reproduce, sheep_reprod_rule,\n id(S), hom(S, s_reprod_r)) |> tryrule;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Reproduction-test","page":"Lotka Volterra","title":"Reproduction test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin # test\n ex = @acset LV begin\n Sheep=1; Wolf=1; V=2;\n countdown=[20,30]\n sheep_loc=1; sheep_eng=10; sheep_dir=:W\n wolf_loc=2; wolf_eng=5; wolf_dir=:N\n end\n\n expected = copy(ex)\n add_part!(expected,:Sheep)\n expected[:sheep_eng] = [5, 5]\n expected[:sheep_loc] = [1, 1]\n expected[:sheep_dir] = [:W, :W]\n\n @test is_isomorphic(rewrite(sheep_reprod_rule,ex),expected)\n rewrite!(sheep_reprod_rule,ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Grass-increments","page":"Lotka Volterra","title":"Grass increments","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"g_inc_n = deepcopy(G)\nset_subpart!(g_inc_n, 1, :countdown, 0)\nrem_part!(g_inc_n, :Time, 1);\n\ng_inc_rule = Rule(id(G), id(G);\n ac=[AppCond(hom(G, g_inc_n), false)],\n expr=(Time=[vs -> only(vs) - 1],));\n\ng_inc = RuleApp(:GrassIncrements, g_inc_rule, G) |> tryrule;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Grass-incrementing-test","page":"Lotka Volterra","title":"Grass incrementing test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n Sheep = 1; V = 3; E = 2\n src = [1, 2]; tgt = [2, 3]\n sheep_loc = 2; sheep_eng = [3]; sheep_dir = [:N]\n countdown = [1, 10, 2]; dir = fill(:N, 2)\n end\n expected = @acset LV begin\n Sheep = 1; V = 3; E = 2\n src = [1, 2]; tgt = [2, 3]\n sheep_loc = 2; sheep_eng = [3]; sheep_dir = [:N]\n countdown = [0, 10, 2]; dir = fill(:N, 2)\n end\n @test is_isomorphic(rewrite(g_inc_rule, ex), expected)\n rewrite!(g_inc_rule, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Assembling-rules-into-a-recipe","page":"Lotka Volterra","title":"Assembling rules into a recipe","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Now we can assemble our building block transitions into a large wiring diagram characterizing the flow of the overall ABM simulation. In addition to the blue rewrite rule blocks, we have red (probabilistic) control flow blocks and yellow Query blocks.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"general = mk_sched((;), (init=:S,), N, (\n turn=const_cond([1.0, 2.0, 1.0], S; name=:turn),\n maybe=const_cond([0.1, 0.9], S; name=:reprod),\n lft=sheep_rotate_l,\n rght=sheep_rotate_r,\n fwd=sheep_fwd,\n repro=sheep_reprod,\n starve=sheep_starve),\n quote\n out_l, out_str, out_r = turn(init)\n moved = fwd([lft(out_l), out_str, rght(out_r)])\n out_repro, out_no_repro = maybe(moved)\n return starve([repro(out_repro), out_no_repro])\n end);\n\nview_sched(general; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"The above was content common to wolves and sheep. The difference is how they eat.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"sheep = sheep_eat ⋅ general; # executed once per sheep\n\nview_sched(sheep; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We use the swap data migration functor F to translate the sheep routine into a wolf one so that it can be composed with the wolf eating step.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"wolf = wolf_eat ⋅ F(general); # executed once per wolf\n\nview_sched(wolf; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Do all sheep, then all wolves, then all daily operations","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"cycle = (agent(sheep; n=:sheep, ret=I)\n ⋅\n agent(wolf; n=:wolves, ret=I)\n ⋅\n agent(g_inc; n=:grass))\n\nview_sched(cycle; names=N)\n\n#=\nWrap the whole thing in a while loop. Also apply the F2 migration to give\neverything coordinates.\n=#\n\noverall = while_schedule(cycle, curr -> nparts(curr, :Wolf) >= 0) |> F2\n\nview_sched(overall; names=F2(N))","category":"page"},{"location":"generated/lotka_volterra/#Running-the-simulation","page":"Lotka Volterra","title":"Running the simulation","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"X = initialize(3, 0.25, 0.25); # 3 × 3 grid, 2 sheep + wolves\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Encourage something exciting to happen by placing a wolf on top of a sheep","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"X[1, :wolf_loc] = X[1, :sheep_loc]\nX[1, :wolf_dir] = X[1, :sheep_dir]\n\nview_LV(X)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Run the simulation for 100 steps","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"res = interpret(overall, X; maxstep=100);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Visualizing-the-results","page":"Lotka Volterra","title":"Visualizing the results","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Run this line to view the trajectory in the generated traj folder","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"view_traj(overall, res[1:10], view_LV; agent=true, names=F2(N));\nnothing #hide","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"EditURL = \"../../literate/ptg_simple.jl\"","category":"page"},{"location":"generated/ptg_simple/#Slice-Bread","page":"Slice Bread","title":"Slice Bread","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"using PrettyTables\n\nusing Catlab\nusing AlgebraicRewriting","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Create an ontology by defining a finite presentation of a freely generated category using @present macro","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"About the world: The Bread World Ontology has the types Thing, BreadLoaf, Countertop, and Stool. The Breadloaf, Countertop, and Stool types have morphisms to Thing that represent is-a relationships. The InOn type can be used to encode a set relation (as opposed to a function) that was two morphisms going to Thing. One morphism points out the LHS of the relation and the other morphism point out the RHS of the relation.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"@present OntBreadWorld(FreeSchema) begin\n Thing::Ob\n BreadLoaf::Ob\n Countertop::Ob\n Stool::Ob\n\n BreadLoafIsThing::Hom(BreadLoaf, Thing) # is-a\n CountertopIsThing::Hom(Countertop, Thing) # is-a\n StoolIsThing::Hom(Stool, Thing) # is-a\n\n InOn::Ob\n inOn_l::Hom(InOn, Thing)\n inOn_r::Hom(InOn, Thing)\nend","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Visualize the ontology","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"to_graphviz(OntBreadWorld)","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Make the ontology an acset type","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"@acset_type BreadWorld(OntBreadWorld)","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Construct rule by defining a span in the category of ACSets","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Use the @acset macro to define an ACSet functor. The LHS refers to a type (or object) in our ontology and the RHS defines the set assignment using FinFunctions. For this, you need to completely specify the ACSet functor, i.e. every object and morphism in the index category must be specified.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"About the rule: This rule moves a breadloaf from a countertop to a stool.","category":"page"},{"location":"generated/ptg_simple/#Left-ACSet","page":"Slice Bread","title":"Left ACSet","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"L = @acset BreadWorld begin\n Thing = 3\n BreadLoaf = 1\n Countertop = 1\n Stool = 1\n\n BreadLoafIsThing = [1]\n CountertopIsThing = [2]\n StoolIsThing = [3]\n\n InOn = 1\n inOn_l = [1]\n inOn_r = [2] # breadloaf is on the countertop\nend","category":"page"},{"location":"generated/ptg_simple/#Middle/Keep-ACSet","page":"Slice Bread","title":"Middle/Keep ACSet","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"The Thing, Breadloaf, Countertop, and Stool types should be held constant. The InOn type will change because we are changing the underlying set function.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"K = @acset BreadWorld begin\n Thing = 3\n BreadLoaf = 1\n Countertop = 1\n Stool = 1\n BreadLoafIsThing = [1]\n CountertopIsThing = [2]\n StoolIsThing = [3]\nend","category":"page"},{"location":"generated/ptg_simple/#Right-ACSet","page":"Slice Bread","title":"Right ACSet","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"R = @acset BreadWorld begin\n Thing = 3\n BreadLoaf = 1\n Countertop = 1\n Stool = 1\n\n BreadLoafIsThing = [1]\n CountertopIsThing = [2]\n StoolIsThing = [3]\n\n InOn = 1\n inOn_l = [1]\n inOn_r = [3] # breadloaf is on the stool\nend","category":"page"},{"location":"generated/ptg_simple/#Left-leg-of-span","page":"Slice Bread","title":"Left leg of span","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"l = ACSetTransformation(K, L, Thing=[1, 2, 3], BreadLoaf=[1], Countertop=[1], Stool=[1])","category":"page"},{"location":"generated/ptg_simple/#Right-leg-of-span","page":"Slice Bread","title":"Right leg of span","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"r = ACSetTransformation(K, R, Thing=[1, 2, 3], BreadLoaf=[1], Countertop=[1], Stool=[1])","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Use AlgebraicRewriting.Rule wrapper to add a rule interface","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"moveBreadRule = Rule(l, r)","category":"page"},{"location":"generated/ptg_simple/#WORLD-STATE","page":"Slice Bread","title":"WORLD STATE","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Define a world state using the @acset macro. This is the ACSet way of specifying an ACSet. For this, you need to completely specify the ACSet functor, i.e. every object and morphism in the index category must be specified. The ACSets must be specified in terms of FinFunctions.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"About the world state: In this world state, there are two countertops, one stool, and one breadloaf. All of these amount to four things. The breadloaf is on the first countertop.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"state = @acset BreadWorld begin\n Thing = 4\n BreadLoaf = 1\n Countertop = 2\n Stool = 1\n\n BreadLoafIsThing = [1]\n CountertopIsThing = [2, 3] # there are two countertops\n StoolIsThing = [4]\n\n InOn = 1\n inOn_l = [1] # breadloaf is on the countertop 1\n inOn_r = [2]\nend","category":"page"},{"location":"generated/ptg_simple/#Apply-Rule","page":"Slice Bread","title":"Apply Rule","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Use the AlgebraicRewriting.get_matches(::Rule{T}, ::ACSet) utility function to find matches between the rule and the state.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"matches = get_matches(moveBreadRule, state)","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Take the first match","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"match = matches[1]","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Compute the new world state after rewriting","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"new_state = rewrite_match(moveBreadRule, match)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"EditURL = \"../../literate/full_demo.jl\"","category":"page"},{"location":"generated/full_demo/#Full-Demo","page":"Full Demo","title":"Full Demo","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"using AlgebraicRewriting, Catlab, AlgebraicPetri, DataMigrations\nusing Test","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"This is a self-contained walkthrough of the main features of AlgebraicRewriting. This is a regular julia file that can be run interactively.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Importantly:","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"use Julia 1.10\nactivate the environment in AlgebraicRewriting.jl/docs\ncheck that graphviz is installed locally (test via \"which dot\" in terminal)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Table of contents:","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"DPO\nSPO\nSqPO\nPBPO+\nGeneralizing graphs: C-Sets, Slices, etc.\nApplication conditions\nAttribute variables\nGraph processes\nGeneral purpose programming / agent-based modeling","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"a. Rewrite and Control Flow boxes b. Agents and Query boxes c. Data migration d. Monadic output","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"The VS Code REPL makes it easy to have figures automatically pop up in a side window, so this is the preferred way of interacting with this file. However, if that is not available, your options are to 1.) copy-paste the code into a Jupyter notebook 2.) use the following to_svg function, which will write a graphviz output to a SVG file and can be viewed in a browser. The Julia pipe syntax |> allows you to easily append \" |> to_svg \" to a line with a visualization.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"to_svg(G, filename=\"tmp.svg\") =\n open(filename, \"w\") do io\n show(io, \"image/svg+xml\", G)\n end\n\nto_graphviz(path_graph(Graph, 3))","category":"page"},{"location":"generated/full_demo/#1.-DPO","page":"Full Demo","title":"1. DPO","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We construct a rule by providing a span, L ← I → R","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L = path_graph(Graph, 2) # • → •\nI = Graph(1) # •\nR = @acset Graph begin\n V = 1\n E = 1\n src = 1\n tgt = 1\nend # •↺\nl = ACSetTransformation(I, L; V=[1]) # graph homomorphism data\nr = ACSetTransformation(I, R; V=[1])\nrule = Rule(l, r)\n\nG = path_graph(Graph, 5) # • → • → • → • → •\nm = only(get_matches(rule, G)) # only one match which satisfies dangling condition","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Provided a specific match (m), we can use the rule to rewrite the graph (G) using rewrite_match(rule, m).","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"res = rewrite_match(rule, m) # • → • → • → •↺\nto_graphviz(res; node_labels=true)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Note that C-Sets are morally regarded up to isomorphism - in particular, limits and colimits may modify the orderings of edges/vertices","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"expected = @acset Graph begin\n V = 4\n E = 4\n src = [1, 2, 3, 4]\n tgt = [2, 3, 4, 4]\nend\n@test is_isomorphic(expected, res)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can also specify the rule via a colimit-of-representables (i.e. generators and relations) syntax. As your schema gets bigger, this becomes more and more convenient. Assigning temporary tags, e.g. e, v, eᵣ to the C-Set elements can also be helpful.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"yG = yoneda_cache(Graph, clear=true); # compute representables\n\nrule2 = Rule(@migration(SchRulel, SchGraph, begin\n L => @join begin\n e::E\n end\n K => @join begin\n v::V\n end\n R => @join begin\n eᵣ::E\n src(eᵣ) == tgt(eᵣ)\n end\n l => begin\n v => src(e)\n end\n end), yG)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can also rewrite without a match (and let it pick an arbitrary match).","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"@test res == rewrite(rule, G)","category":"page"},{"location":"generated/full_demo/#2.-SPO","page":"Full Demo","title":"2. SPO","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rules are by default DPO, but if we specify a type parameter we can change the semantics","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"rule_spo = Rule{:SPO}(l, r) # (same data as before)\n\n@test length(get_matches(rule_spo, G)) == 4 # there are now four matches\nres = rewrite(rule_spo, G)\nto_graphviz(res)\n@test is_isomorphic(res, path_graph(Graph, 3) ⊕ R)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Note: ⊕ and ⊗ are shorthand for (co)products Tip: Julia lets you easily write unicode symbols via \"\\\" followed by a LaTeX name, then hit \"Tab\" to convert the symbol","category":"page"},{"location":"generated/full_demo/#3.-SqPO","page":"Full Demo","title":"3. SqPO","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"If we duplicate a vertex with an incident edge, it will duplicate the edge","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L = Graph(1)\nI = Graph(2)\nR = path_graph(Graph, 2)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can use automated homomorphism search to reduce the tedium of specifying data manually. In this case, there is a unique option.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"l = homomorphism(I, L)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"There are many constraints we can put on the search, such as being monic.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"r = homomorphism(I, R; monic=true)\n\nrule_sqpo = Rule{:SqPO}(l, r) # same data as before)\n\n\nG = star_graph(Graph, 6) # a 5-pointed star\nto_graphviz(G; prog=\"neato\") # changing \"prog\" can sometimes make it look better\n\nm = ACSetTransformation(Graph(1), G; V=[6]) # point at the center\nres = rewrite_match(rule_sqpo, m)\nto_graphviz(res; prog=\"neato\")","category":"page"},{"location":"generated/full_demo/#4.-PBPO","page":"Full Demo","title":"4. PBPO+","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"PBPO+ requires not merely a span but also additional data for L and K which can be thought of as type graphs. The graph G that we rewrite will be typed over the L' type graph to determine how it is rewritten.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L = Graph(1)\nK = Graph(2)\nl = homomorphism(K, L)\nr = id(K)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We allow edges into and out of the matched vertex as well as edges between the vertices incident to the matched vertex","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L′ = @acset Graph begin\n V = 3\n E = 6\n src = [1, 1, 1, 2, 3, 3]\n tgt = [1, 2, 3, 3, 3, 1]\nend\ntl = ACSetTransformation(L, L′; V=[2]) # 2 is the matched vertex\nto_graphviz(L′; node_labels=true)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"The outneighbors of the matched vertex are duplicated (an edge connects the old ones to the new ones) and the matched vertex is duplicated. The new copy of the matched vertex points at the new ones. It does not have any inneighbors.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"K′ = @acset Graph begin\n V = 5\n E = 9\n src = [1, 1, 1, 2, 3, 3, 3, 4, 5]\n tgt = [1, 2, 3, 3, 3, 1, 5, 5, 5]\nend\ntk = ACSetTransformation(K, K′; V=[2, 4])\nto_graphviz(K′; node_labels=true)\n\nl′ = homomorphism(K′, L′; initial=(V=[1, 2, 3, 2, 3],))\n\nprule = PBPORule(l, r, tl, tk, l′)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Apply to an example vertex (#3) with two inneighbors and one outneighbor.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"G = @acset Graph begin\n V = 4\n E = 5\n src = [1, 1, 2, 3, 4]\n tgt = [2, 3, 3, 4, 4]\nend\nto_graphviz(G; node_labels=true)\n\nm = get_match(prule, G; initial=(V=[3],) => Dict())\n\nres = rewrite_match(prule, m)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"V1 is copied to V2. Outneighbor V5 (w/ loop) is copied to V6, creating an edge","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"to_graphviz(res; node_labels=true)","category":"page"},{"location":"generated/full_demo/#5.-Generalizing-Graphs","page":"Full Demo","title":"5. Generalizing Graphs","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Any data structure which implements the required functions we need can, in principle, be used for rewriting. Importantly this includes pushout_complement, pushout, and homomorphism search. These are all implemented generically for any C-Set schema (allowing us to rewrite Petri nets, Semisimplicial sets, etc.)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Here we'll do rewriting in graphs sliced over •⇆•, which is isomorphic to the category of (whole-grain) Petri nets, with States and Transitions.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"function graph_slice(s::Slice)\n h = s.slice\n V, E = collect.([h[:V], h[:E]])\n g = dom(h)\n (S, T), (I, O) = [[findall(==(i), X) for i in 1:2] for X in [V, E]]\n nS, nT, nI, nO = length.([S, T, I, O])\n findS, findT = [x -> findfirst(==(x), X) for X in [S, T]]\n to_graphviz(@acset AlgebraicPetri.PetriNet begin\n S = nS\n T = nT\n I = nI\n O = nO\n is = findS.(g[I, :src])\n it = findT.(g[I, :tgt])\n ot = findT.(g[O, :src])\n os = findS.(g[O, :tgt])\n end)\nend;\nnothing #hide","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"This is the graph we are slicing over.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"two = @acset Graph begin\n V = 2\n E = 2\n src = [1, 2]\n tgt = [2, 1]\nend","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Define a rule which deletes a [T] -> S edge","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L_ = path_graph(Graph, 2)\nL = Slice(ACSetTransformation(L_, two, V=[2, 1], E=[2])) # [T] ⟶ (S)\ngraph_slice(L)\n\nI_ = Graph(1)\nI = Slice(ACSetTransformation(I_, two, V=[2])) # [T]\nR_ = Graph(2)\nR = Slice(ACSetTransformation(R_, two, V=[2, 1])) # [T] (S)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Using homomorphism search in the slice category","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"rule = Rule(homomorphism(I, L), homomorphism(I, R))\n\nG_ = path_graph(Graph, 3)\nG = Slice(ACSetTransformation(G_, two, V=[1, 2, 1], E=[1, 2])) # (S) ⟶ [T] ⟶ (S)\ngraph_slice(G)\n\nres = rewrite(rule, G) # (S) ⟶ [T] (S)\ngraph_slice(res)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"While the vast majority of functionality is focused on ACSets at the present moment, but there is nothing in principle which limits this.","category":"page"},{"location":"generated/full_demo/#6.-Application-conditions","page":"Full Demo","title":"6. Application conditions","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can construct commutative diagrams with certain edges left unspecified or marked with ∀ or ∃. If only one edge is left free, we can treat the diagram as a boolean function which tests whether the morphism makes the specified paths commute (or not commute). This generalizes positive/negative application conditions and lifting conditions, but because those are most common there are constructors AppCond and LiftCond to make these directly.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":" ∀","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"[↻•] → ? ↓ ↗ ∃ ↓ [↻•⟶•] → [↻•⟶•⟵•↺]","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Every vertex with a loop also has a map to the vertex marked by the bottom map.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"t = terminal(Graph) |> apex\nlooparr = @acset_colim yG begin\n (e1, e2)::E\n src(e1) == tgt(e1)\n src(e1) == src(e2)\nend\n\nv = homomorphism(t, looparr)\nloop_csp = @acset Graph begin\n V = 3\n E = 4\n src = [1, 3, 1, 3]\n tgt = [1, 3, 2, 2]\nend\nb = homomorphism(looparr, loop_csp; monic=true)\nconstr = LiftCond(v, b)\n\n@test !apply_constraint(constr, homomorphism(t, loop_csp))\n@test apply_constraint(constr, b)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can combining constraints with logical combinators.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"match vertex iff it has 2 or 3 self loops","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"one, two, three, four, five = [@acset(Graph, begin\n V = 1\n E = n\n src = 1\n tgt = 1\nend) for n in 1:5]\n\nc2 = AppCond(homomorphism(Graph(1), two); monic=true) # PAC\nc3 = AppCond(homomorphism(Graph(1), four), false; monic=true) # NAC\nconstr = c2 ⊗ c3 # logical conjunction: 2 ≤ |E| < 4\n\nrule = Rule(id(Graph(1)), id(Graph(1)); ac=[constr])\n\nG = two ⊕ three ⊕ two ⊕ four ⊕ five ⊕ one\n\n@test length(get_matches(rule, G)) == 3","category":"page"},{"location":"generated/full_demo/#7.-Attribute-variables","page":"Full Demo","title":"7. Attribute variables","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Normally ACSet morphisms must match attribute values exactly, i.e. a weighted graph edge of 8.3 can only be mapped to another edge weighted at 8.3. This becomes very restricted, especially when we want to do some simple computations with attribute values (e.g. when merging two edges, add their values together)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"A recent extension of ACSets makes this possible - each attribute type comes equipped with a finite set of \"variables\" which can be mapped to any concrete value (or another variable).","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"yWG = yoneda_cache(WeightedGraph{Int}; clear=true);\nL = @acset_colim yWG begin\n (e1, e2)::E\n src(e1) == src(e2)\n tgt(e1) == tgt(e2)\nend\nI = WeightedGraph{Int}(2)\nR = @acset WeightedGraph{Int} begin\n V = 2\n E = 1\n Weight = 1\n src = 1\n tgt = 2\n weight = [AttrVar(1)]\nend\n\nl = homomorphism(I, L; monic=true)\nr = homomorphism(I, R; monic=true)\nrule = Rule(l, r; monic=[:E], expr=Dict(:Weight => [xs -> xs[1] + xs[2]]))\n\nG = @acset WeightedGraph{Int} begin\n V = 1\n E = 3\n src = 1\n tgt = 1\n weight = [10, 20, 100]\nend\n\n@test rewrite(rule, G) == @acset WeightedGraph{Int} begin\n V = 1\n E = 2\n src = 1\n tgt = 1\n weight = [30, 100]\nend","category":"page"},{"location":"generated/full_demo/#8.-Graph-processes","page":"Full Demo","title":"8. Graph processes","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"A sequence of rewrite applications can be given a poset structure where α ≤ β means that the rule application α needed to occur before β. This is computed via analyzing the colimit of all the partial maps induced by the rewrites.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"using AlgebraicRewriting.Processes: RWStep, find_deps\n\nG0, G1, G2, G3 = Graph.([0, 1, 2, 3])","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Delete a node","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rule1 = Span(create(G1), id(G0));\nnothing #hide","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Merge two nodes","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rule2 = Span(id(G2), homomorphism(G2, G1));\nnothing #hide","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Add a node","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rule3 = Span(id(G0), create(G1))\n\nR1, R2, R3 = [Rule(l, r) for (l, r) in [Rule1, Rule2, Rule3]]","category":"page"},{"location":"generated/full_demo/#9.-Trajectory","page":"Full Demo","title":"9. Trajectory","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Step 1: add node 3 to G2","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"M1 = create(G2)\nCM1 = ACSetTransformation(G1, G3; V=[3])\nPmap1 = Span(id(G2), ACSetTransformation(G2, G3; V=[1, 2]))\nRS1 = RWStep(Rule3, Pmap1, M1, CM1)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Step 2: merge node 2 and 3 to yield a G2","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"M2 = ACSetTransformation(G2, G3; V=[2, 3])\nCM2 = ACSetTransformation(G1, G2; V=[2])\nPmap2 = Span(id(G3), ACSetTransformation(G3, G2; V=[1, 2, 2]))\nRS2 = RWStep(Rule2, Pmap2, M2, CM2)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Step 3: delete vertex 1","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"M3 = ACSetTransformation(G1, G2; V=[1])\nCM3 = create(G1)\nPmap3 = Span(ACSetTransformation(G1, G2; V=[2]), id(G1))\nRS3 = RWStep(Rule1, Pmap3, M3, CM3)\n\n\nsteps = [RS1, RS2, RS3]\n\ng = find_deps(steps)\nto_graphviz(g; node_labels=true)\n\nexpected = @acset Graph begin\n V = 3\n E = 1\n src = 1\n tgt = 2\nend\n@test expected == g","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Interface that just uses rules and match morphisms: The matches needed to be updated to reflect the particular isomorph that DPO rewriting produces when applying the rule.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"σ₂ = ACSetTransformation(G2, G2; V=[2, 1])\nσ₃ = ACSetTransformation(G3, G3; V=[3, 1, 2])\n\ng′ = find_deps([R3 => M1, R2 => M2 ⋅ σ₃, R1 => M3 ⋅ σ₂])\n@test g′ == g","category":"page"},{"location":"#AlgebraicRewriting.jl","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"CurrentModule = AlgebraicRewriting","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Algebraic rewriting is a context-aware find-and-replace operation that is useful for maintaining structure in various scenarios. This package provides tools for such operations in Julia, ensuring that rewrite rules adhere to structures defined using ACSets (see ACSets.jl and Catlab.jl). This documentation provides a basic guide to using the AlgebraicRewriting package in Julia. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This page will provide you with a gentle overview of how to design and apply rewrite rules for a simple ACSet. More sophisticated examples can be found in the side-bar.","category":"page"},{"location":"#Setup-Environment","page":"AlgebraicRewriting.jl","title":"Setup Environment","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To begin, set up your environment by importing necessary packages.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"using Catlab\nusing AlgebraicRewriting\nusing DataMigrations","category":"page"},{"location":"#Design-a-rewrite-rule","page":"AlgebraicRewriting.jl","title":"Design a rewrite rule","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"The general process for designing a rewrite rule is as follows:","category":"page"},{"location":"#1.-Define-your-schema","page":"AlgebraicRewriting.jl","title":"1. Define your schema","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"A schema defined by a finite presentation of a generalized algebraic theory model using generators, Ob, Hom, AttrType, and Attr.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"@present SchSportsTeam(FreeSchema) begin\n Player::Ob\n Team::Ob\n Member::Ob\n IsMember::Hom(Member, Player)\n MemberOf::Hom(Member, Team)\n\n Name::AttrType\n PlayerHasName::Attr(Player, Name)\n TeamHasName::Attr(Team, Name)\nend\nto_graphviz(SchSportsTeam)","category":"page"},{"location":"#2.-Create-the-schema-type","page":"AlgebraicRewriting.jl","title":"2. Create the schema type","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Data for rules are stored in a data structure called an ACSet. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"@acset_type SportsTeam(SchSportsTeam)","category":"page"},{"location":"#3.-Define-rule-parts","page":"AlgebraicRewriting.jl","title":"3. Define rule parts","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"A rewrite rule consists of a span of ACSets (L <-l- K -r-> R), namely three ACSets (L, K, R) and two natural transformations (l, r):","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Left ACSet, L, is the pre-condition for the rule to be applied.\nKeep ACSet, K, is the data for the part of the state that remain consistent when the rule is applied.\nRight ACSet, R, is the effect of the rule.\nLeft transformation, l, embeds K in L.\nRight transformation, r, embed K in R.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To define a rule, all five parts need to be defined. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"It is possible to insert data according to the schema using a static approach or the colimit-of-representables approach.","category":"page"},{"location":"#Static-Instantiation-(@acset)","page":"AlgebraicRewriting.jl","title":"Static Instantiation (@acset)","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the static approach, you must fully specify the ACSet functors and natural transformation. Here is a rule that defines the ACSet statically. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"In this example, the rule swaps players, one from each team. AttrVar.(1:2), or [AttrVar(1), AttrVar(2)], are used as variable placeholders for the names of the players. This allows the rule to be applied independent of player names, as long as two players are specified from opposing teams. Contrastingly, [\"Home\", \"Away\"], are specified explicitly and, therefore, this rule can only be applied to teams whose names are \"Home\" and \"Away\"","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"# Both L and R are the same: two players are members of a Home and Away team\nL = R = @acset SportsTeam{String} begin\n Player = 2; Team = 2; Member = 2; Name = 2\n IsMember = [1, 2]; MemberOf = [1, 2]\n PlayerHasName = AttrVar.(1:2)\n TeamHasName = [\"Home\", \"Away\"]\nend\n# K is missing the Member relation. L <- K removes the two players' memberships\n# and K -> R adds in a new membership relation.\nK = @acset SportsTeam{String} begin\n Player = 2; Team = 2; Name = 2\n PlayerHasName = AttrVar.(1:2)\n TeamHasName = [\"Home\", \"Away\"]\nend\n\n# Manually specify K->L and K->R\n# Important that the player removed from Home (as determined by l: K->L) is \n# assigned (via r: K->R) to the player which is added to away, and vice-versa.\nl = ACSetTransformation(K, L, Player=[1,2], Team=[1, 2], Name=AttrVar.([1,2]))\nr = ACSetTransformation(K, R, Player=[2,1], Team=[1, 2], Name=AttrVar.([2,1])) # swap\n\n# Alternatively we could use automated search, as there are the only two maps \n# K->L (same as K->R because L=R) that do not merge the two players together \nl, r = homomorphisms(K, L; monic=true) # ('monic' = \"no merging allowed\")","category":"page"},{"location":"#Colimit-of-representables-instantiation-(@acset_colim)","page":"AlgebraicRewriting.jl","title":"Colimit-of-representables instantiation (@acset_colim)","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the colimit-of-representables approach, you only need to specify relevant objects and morphism parts. Shown here is the translation of the above rule using @acset_colim.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"ySportsTeam = yoneda(SportsTeam{String})\nL = R = @acset_colim ySportsTeam begin\n (p1, p2)::Player\n (t1, t2)::Team\n (m1, m2)::Member\n IsMember(m1) == p1\n IsMember(m2) == p2\n MemberOf(m1) == t1\n MemberOf(m2) == t2\n TeamHasName(t1) == \"Home\"\n TeamHasName(t2) == \"Away\"\nend # we did not specify PlayerHasName, so it's left generic\nK = @acset_colim ySportsTeam begin\n (t1, t2)::Team\n (p1, p2)::Player\n TeamHasName(t1) == \"Home\"\n TeamHasName(t2) == \"Away\"\nend\nl, r = homomorphisms(K, L; monic=true) # same as above because K,L,R are the same","category":"page"},{"location":"#4.-Construct-the-rule","page":"AlgebraicRewriting.jl","title":"4. Construct the rule","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Use the AlgebraicRewriting.Rule constructor to create the rule. This assumes that a double-pushout (DPO) rewrite rule is being constructed. You may also construct an single-pushout (SPO), sesqui-pushout (SqPO), or pullback-pushout (PBPO) rule.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"rule = Rule{:DPO}(l, r)","category":"page"},{"location":"#Apply-the-rule","page":"AlgebraicRewriting.jl","title":"Apply the rule","text":"","category":"section"},{"location":"#5.-Define-the-initial-state.","page":"AlgebraicRewriting.jl","title":"5. Define the initial state.","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Similarly, you can choose to define the acset using the static approach or the colimit-of-representable approach.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the static approach, you must fully specify the ACSet for the initial state.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"state = @acset SportsTeam{String} begin\n Player = 4; Member = 4; Team = 2\n IsMember = [1, 2, 3, 4]; MemberOf = [1, 1, 2, 2]\n TeamHasName = [\"Home\", \"Away\"]\n PlayerHasName = [\"Jordan\", \"Alex\", \"Casey\", \"Taylor\"]\nend","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the colimit-of-representable approach, you only need to specify relevant objects and morphism parts.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"state = @acset_colim ySportsTeam begin\n (p1, p2, p3, p4)::Player\n (m1, m2, m3, m4)::Member\n (t1, t2)::Team\n IsMember(m1) == p1; IsMember(m2) == p2; IsMember(m3) == p3; IsMember(m4) == p4\n MemberOf(m1) == t1; MemberOf(m2) == t1; MemberOf(m3) == t2; MemberOf(m4) == t2\n PlayerHasName(p1) == \"Jordan\"\n PlayerHasName(p2) == \"Alex\"\n PlayerHasName(p3) == \"Casey\"\n PlayerHasName(p4) == \"Taylor\"\n TeamHasName(t1) == \"Home\"\n TeamHasName(t2) == \"Away\"\nend","category":"page"},{"location":"#6.-Identify-the-match-from-the-rule-to-the-state","page":"AlgebraicRewriting.jl","title":"6. Identify the match from the rule to the state","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This can be done manually or automatically. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To manually identify the match, fully-specify an ACSet transformation. For this example, we would like to rule to swap p2::Player and p3::Player","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"pattern_match = ACSetTransformation(L, state, Player=[2, 3], Member=[2, 3], \n Team=[1, 2], Name=[\"Alex\", \"Casey\"])","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To automatically identify the match, use the backtracking search algorithm provided by AlgebraicRewriting. This may return multiple matches, so you can provide logic for deciding which match to select. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"pattern_match = homomorphism(L, state; initial=(Name=[\"Alex\", \"Casey\"],))\n\nmatches = get_matches(rule, state)# get all four possible matches, then pick one","category":"page"},{"location":"#7.-Apply-the-rewrite-rule","page":"AlgebraicRewriting.jl","title":"7. Apply the rewrite rule","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This executes the rewrite process using using the defined rule and match.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"result = rewrite_match(rule, pattern_match)","category":"page"},{"location":"#Authors","page":"AlgebraicRewriting.jl","title":"Authors","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This documentation is maintained by Angeline Aguinaldo and Kristopher Brown.","category":"page"}] +[{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"EditURL = \"../../literate/game_of_life.jl\"","category":"page"},{"location":"generated/game_of_life/#Conway's-Game-of-Life","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"This is a demonstration of the game of life as an agent-based model.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We start with importing some libraries.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"using AlgebraicRewriting\nusing Catlab, Catlab.Graphs, Catlab.CategoricalAlgebra, Catlab.Theories\nimport Catlab.Graphics: to_graphviz\nusing Catlab.Graphics.Graphviz: Attributes, Statement, Node, Edge, Digraph\nusing PrettyTables\nusing Luxor","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The game of life has two rules: one which turns living things dead, and one that brings dead things to life. We model the terrain as a symmetric graph: cells are vertices. Neighboring cells have edges between them.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Implementation wise, if we are going to update cells one at a time, we must keep track of two bits of information (the cell's living status for the current timestep and whether it will be alive in the next timestep). Thus we need helper rule to overwrite the \"current\" life status with the \"next\" life status at the end of each timestep.","category":"page"},{"location":"generated/game_of_life/#Ontology","page":"Conway's Game of Life","title":"Ontology","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Defining an ontology is stating what data is required to specify a state of the simulation at some point in time. In AlgebraicJulia, this is done via declaring a Presentation, i.e. a database schema. Objects (Ob, or tables) are types of entities. Homs (Hom, or foreign keys) are functional relationships between the aforementioned entities. AttrTypes are placeholders for Julia types, which are assigned to Ob via attributes (Attr).","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The schema below extends the schema for directed symmetric graphs, which consists in two tables (E and V, for edges and vertices) and two homs (src and tgt, E→V). Furthermore a hom inv: E→E enforces that each edge is paired with its opposite-pointing edge.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The schema below says there are two more types of entities, Curr and Next. Think of these as little tokens that can be assigned to vertices to mark them as currently-alive or to-be-alive-in-the-next-timestep, respectively. Thus, we can also thinking of them as picking out subsets of V via the maps curr and next.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"@present SchLife <: SchSymmetricGraph begin\n (Curr, Next)::Ob\n curr::Hom(Curr, V)\n next::Hom(Next, V)\nend\n\n@acset_type Life(SchLife, part_type=BitSetParts) <: AbstractSymmetricGraph\n\nto_graphviz(SchLife; prog=\"dot\")","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We can further extend this schema with an additional attribute of (x,y) coordinates for every vertex. This is nice for visualization but is otherwise unnecessary when doing the actual agent-based modeling. So what we will do is build our model with the Life schema and then run our model with the LifeCoords schema.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"@present SchLifeCoords <: SchLife begin\n Coords::AttrType\n coords::Attr(V, Coords)\nend\n\n@acset_type AbsLifeCoords(SchLifeCoords, part_type=BitSetParts) <: AbstractSymmetricGraph\n\nconst LifeCoords = AbsLifeCoords{Tuple{Int,Int}};\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#Data-migration-functors","page":"Conway's Game of Life","title":"Data migration functors","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We ought to be able to take a state of the world (with no coordinate information) and obtain a state of the world with coordinates (the canonical way to do this is to assign \"variables\" for the values of the coordinates).","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"F = Migrate(SchLifeCoords, LifeCoords; delta=false); # adds coordinates\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"F⁻¹ = DeltaMigration(FinFunctor(idₒ, idₘ, SchLife, SchLifeCoords)); # removes coordinates","category":"page"},{"location":"generated/game_of_life/#Helper-functions","page":"Conway's Game of Life","title":"Helper functions","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Functions to help us create a grid.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function make_grid(curr::AbstractMatrix, next=nothing)\n n, m = size(curr)\n n == m || error(\"Must be square\")\n X, coords = LifeCoords(), Dict()\n for i in 1:n\n for j in 1:n\n coords[i=>j] = add_vertex!(X; coords=(i, j))\n if Bool(curr[i, j])\n add_part!(X, :Curr, curr=coords[i=>j])\n end\n if !isnothing(next) && Bool(next[i, j])\n add_part!(X, :Curr, curr=coords[i=>j])\n end\n end\n end\n for i in 1:n\n for j in 1:n\n if i < n\n add_edge!(X, coords[i=>j], coords[i+1=>j])\n end\n if j < n\n add_edge!(X, coords[i=>j], coords[i=>j+1])\n end\n if i < n && j < n\n add_edge!(X, coords[i=>j], coords[i+1=>j+1])\n end\n if i < n && j > 1\n add_edge!(X, coords[i=>j], coords[i+1=>j-1])\n end\n end\n end\n X\nend\n\nmake_grid(n::Int, random=false) = make_grid((random ? rand : zeros)(Bool, (n, n)));\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Functions to help us visualize a grid. Although we have no such constraint, we'll expect any LifeCoords instance to be a regular grid (for the purposes of visualization). When that's the case, we can visualize the game state using plaintext.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function view_life(f::ACSetTransformation, pth=tempname())\n v = collect(f[:V])\n view_life(codom(f), pth; star=isempty(v) ? nothing : only(v))\nend\n\nfunction view_life(X::LifeCoords, pth=tempname(); star=nothing)\n n = Int(sqrt(nparts(X, :V)))\n coords = Dict([(i, j) => findfirst(==((i, j)), X[:coords])\n for (i, j) in Iterators.product(1:n, 1:n)])\n mat = pretty_table(String, reduce(hcat, map(1:n) do i\n map(1:n) do j\n c, x = [!isempty(incident(X, coords[(i, j)], x)) for x in [:curr, :next]]\n res = c ? (x ? \"O\" : \"o\") : (x ? \"X\" : \"x\")\n return res * ((star == coords[(i, j)]) ? \".\" : \"\")\n end\n end); show_header=false, tf=tf_markdown)\n open(pth, \"w\") do io\n write(io, mat)\n end\n return mat\nend\n\ninit = make_grid(3, true)\nview_life(init) |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We can also visualize a grid with a distinguished agent. Here an agent living in a game state X is a map A → X where A is the shape of the agent. The only kind of agent we'll consider in this model is that of a lone vertex.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Note that A below is defined without coordinates, whereas init is an instance of LifeCoords. So in order to relate them via a mapping (which requires them to share a schema) we promote A to LifeCoords using the data migration, F.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"A = Life(1)\nview_life(homomorphism(F(A), init)) |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We must also work with miniature game states that are not grids in order for us to define the dynamics, as they are what the patterns and replacements of rewrite rules are made of. In order to visualize these, we will use another visualization function.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function view_life_graph(X::Union{Life,LifeCoords}, pth=tempname(); star=nothing)\n pg = PropertyGraph{Any}(; prog=\"neato\", graph=Dict(),\n node=Dict(:shape => \"circle\", :style => \"filled\", :margin => \"0\"),\n edge=Dict(:dir => \"none\", :minlen => \"1\"))\n add_vertices!(pg, nparts(X, :V))\n for v in vertices(X)\n set_vprop!(pg, v, :fillcolor, isempty(incident(X, v, :curr)) ? \"red\" : \"green\")\n isempty(incident(X, v, :next)) || set_vprop!(pg, v, :penwidth, \"4.0\")\n set_vprop!(pg, v, :label, star == v ? \"*\" : \"\")\n end\n for e in filter(e -> X[e, :inv] > e, edges(X))\n add_edge!(pg, X[e, :src], X[e, :tgt])\n end\n G = to_graphviz(pg)\n open(pth, \"w\") do io\n show(io, \"image/svg+xml\", G)\n end\n G\nend;\n\nview_life_graph(init)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Now we make some helper functions to construct important ACSets and maps between them. We start with a single vertex which is marked as to-be-alive in the next time step.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Next() = @acset Life begin V = 1; Next = 1; next = 1 end;\n\nview_life_graph(Next())","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We also want to refer to a vertex which is alive in the current time step","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Curr() = @acset Life begin V = 1; Curr = 1; curr = 1 end;\nview_life_graph(Curr())","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We also want these where we have a morphism incoming from a vertex.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"to_next() = homomorphism(Life(1), Next());\nto_curr() = homomorphism(Life(1), Curr());\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We make a helper for cells connected to n living neighbors","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"function living_neighbors(n::Int; alive=false)\n X = Life(1)\n alive && add_part!(X, :Curr, curr=1)\n for _ in 1:n\n v = add_part!(X, :V)\n add_part!(X, :Curr, curr=v)\n add_edge!(X, v, 1)\n end\n X\nend\n\nview_life_graph(living_neighbors(3))","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We can control whether the central cell is itself alive or not","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"view_life_graph(living_neighbors(3; alive=true))","category":"page"},{"location":"generated/game_of_life/#Rules","page":"Conway's Game of Life","title":"Rules","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We have finished specifying what makes up a simulation state, and next is to define what sorts of transitions are possible. This is done by declaring rewrite rules.","category":"page"},{"location":"generated/game_of_life/#A-dead-cell-becomes-alive-iff-exactly-3-living-neighbors","page":"Conway's Game of Life","title":"A dead cell becomes alive iff exactly 3 living neighbors","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"BirthP1 = living_neighbors(3) # must have 3 neighbors\nBirthN1 = living_neighbors(4) # forbid the cell to have 4 neighbors\nBirthN2 = Curr() # forbid the cell to be alive (i.e. it's currently dead)\nBP1, BN1, BN2 = homomorphism.(Ref(Life(1)), [BirthP1, BirthN1, BirthN2])\nbac = [AppCond(BP1; monic=true), AppCond.([BN1, BN2], false; monic=true)...]\nBirth = Rule(id(Life(1)), to_next(); ac=bac);\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#A-living-cell-stays-alive-iff-2-or-3-living-neighbors","page":"Conway's Game of Life","title":"A living cell stays alive iff 2 or 3 living neighbors","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"PersistR = @acset Life begin\n V = 1; Curr = 1; Next = 1; curr = 1; next = 1\nend\nPersistP1 = living_neighbors(2; alive=true)\nPersistN1 = living_neighbors(4; alive=true)\nDR, DP1, DN1 = homomorphism.(Ref(Curr()), [PersistR, PersistP1, PersistN1])\npac = [AppCond(DP1; monic=true), AppCond(DN1, false; monic=true)]\nPersist = Rule(id(Curr()), DR; ac=pac);\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#remove-\"Curr\"-status","page":"Conway's Game of Life","title":"remove \"Curr\" status","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"ClearCurr = Rule(to_curr(), id(Life(1)));\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#remove-\"Next\"-status","page":"Conway's Game of Life","title":"remove \"Next\" status","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"ClearNext = Rule(to_next(), id(Life(1)));\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#Copy-\"Next\"-to-\"Curr\"","page":"Conway's Game of Life","title":"Copy \"Next\" to \"Curr\"","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"CopyNext = Rule(to_next(), to_curr());\nnothing #hide","category":"page"},{"location":"generated/game_of_life/#Assembling-rules-into-a-recipe","page":"Conway's Game of Life","title":"Assembling rules into a recipe","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Now we can assemble our building blocks into a large wiring diagram characterizing the flow of the overall ABM simulation. In addition to the blue rewrite rule blocks, we have yellow Query blocks which execute subroutines once per agent (the second output wire) before exiting (the first output wire).","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Give symbolic names to the rewrite rules from before","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"rules = [:Birth => Birth, :Persist => Persist, :ClearCurr => ClearCurr,\n :ClearNext => ClearNext, :CopyNext => CopyNext];\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"All rules have interface of a single distinguished cell, i.e. they are executed from the perspective an agent which is a particular distinguished vertex.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Normally we can consider branching possibilities depending on whether or not the rewrite is successful, but in this simulation we don't do this. tryrule simply merges the two output wires from a rewrite rule box into a single output wire.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"rBirth, rPersist, rClearCurr, rClearNext, rCopyNext =\n [tryrule(RuleApp(n, r, Life(1))) for (n, r) in rules]\n\nview_sched(rBirth)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The first for loop is computing next for all cells","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"update_next = agent(rBirth ⋅ rPersist, Life(1); n=:Cell)\n\nview_sched(update_next)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"The second for loop is overwriting curr with next for all cells","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"next_step = agent(compose(rClearCurr, rCopyNext, rClearNext), Life(1); n=:Cell)\n\nview_sched(next_step)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"We then compose these together and wrap in an overall for loop with a counter.","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"life(n::Int) = for_schedule(update_next ⋅ next_step, n) |> F\n\nconst L = life(1) # Game of life simulation that runs just one (global) timestep\n\nview_sched(L)","category":"page"},{"location":"generated/game_of_life/#Running-the-simulation","page":"Conway's Game of Life","title":"Running the simulation","text":"","category":"section"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Make an initial state","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"G = make_grid([1 0 1 0 1; 0 1 0 1 0; 0 1 0 1 0; 1 0 1 0 1; 1 0 1 0 1])\n\nview_life_graph(G)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"(or, viewed in plaintext)","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"view_life(G) |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Run the simulation","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"res = interpret(L, G; maxstep=1000);\nnothing #hide","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Look at the end state","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"res[end][1] |> codom |> view_life |> println","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"Visualize the results in the traj folder","category":"page"},{"location":"generated/game_of_life/","page":"Conway's Game of Life","title":"Conway's Game of Life","text":"view_traj(L, res[1:10], view_life; agent=true)","category":"page"},{"location":"api/#Library-Reference","page":"Library Reference","title":"Library Reference","text":"","category":"section"},{"location":"api/#Rewrite","page":"Library Reference","title":"Rewrite","text":"","category":"section"},{"location":"api/","page":"Library Reference","title":"Library Reference","text":"Modules = [\n AlgebraicRewriting.Constraints,\n AlgebraicRewriting.Utils,\n AlgebraicRewriting.DPO,\n AlgebraicRewriting.CoNeg,\n AlgebraicRewriting.SPO,\n AlgebraicRewriting.SqPO,\n AlgebraicRewriting.PBPO,\n AlgebraicRewriting.Migration\n]","category":"page"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate-Tuple{CGraph}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","text":"Apply migration to all literals in the constraint\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolAnd","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolAnd","text":"Conjunction of multiple expressions\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolConst","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolConst","text":"Constant, independent of context\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolExpr","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolExpr","text":"Something that, in a context, can be evaluated to a bool\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolNot","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolNot","text":"Negation of an expression\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.BoolOr","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.BoolOr","text":"Disjunction of multiple expressions\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.CGraph","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.CGraph","text":"\"nothing\" means something that will be determined via a quantifier Ints are explicit arguments provided when apply_constraint is called\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.Commutes","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.Commutes","text":"A commutative diagram with multiple parallel paths, asserted to either commute or to not commute\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.Constraint","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.Constraint","text":"A constraint graph and a BoolExpr (which refers to the constraint graph)\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.Quantifier","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.Quantifier","text":"Quantified edge\n\ne - which edge is filled in kind - Exists, Forall, or Exists! st - \"such that\", restrict the domain of quantification via a condition monic - restrict domain of quanitification to only monic matches\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.AppCond","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.AppCond","text":"Constraint a constraint that asserts (or denies) the existence of a triangle commuting.\n\n f₁\n\n(1) <- (2) ∃₂↘ ↓ λ₃ (3)\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.LiftCond-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.LiftCond","text":" ∀₂\n\n(1) → (3) ₁↓ ↗∃₃ ↓ λ₅ (2) → (4) ⁴\n\nTest a map (3)→(4), given maps (1)->(2)->(4). \n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.arity-Tuple{CGraph}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.arity","text":"Number of variables in a constraint graph\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.check_expr-Tuple{CGraph, Commutes}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.check_expr","text":"Validate a commutative diagram constraint makes sense\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.eval_boolexpr-Tuple{Commutes, CGraph, Vector{Union{Nothing, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.eval_boolexpr","text":"Check whether homs are equal by looping over domain.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.get_ob-Tuple{CGraph, Int64, Vector{Union{Nothing, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.get_ob","text":"Get the C-Set associated with a vertex in a CGraph\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Constraints.merge_graphs-Tuple{Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Constraints.merge_graphs","text":"Take two CGraphs and merge them along their overlapping vertices and edges Returns an ACSetColimit\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.Theories.:⊕-Tuple{Constraint, Constraint}","page":"Library Reference","title":"Catlab.Theories.:⊕","text":"Combine two constraints disjunctively, sharing as much of the computation graph as possible.\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.Theories.:⊗-Tuple{Constraint, Constraint}","page":"Library Reference","title":"Catlab.Theories.:⊗","text":"Combine two constraints conjunctively, sharing as much of the computation graph as possible (i.e. pushout along the maximum common subgraph)\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.Rule","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.Rule","text":"Rewrite rules which are (usually) encoded as spans. The L structure encodes a pattern to be matched. The R morphism encodes a replacement pattern to be substituted in. They are related to each other by an interface I with maps: L ⟵ I ⟶ R \n\nA semantics (DPO, SPO, CoNeg, or SqPO) must be chosen.\n\nControl the match-finding process by specifying whether the match is intended to be monic or not, as well as an optional application condition(s) \n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.can_match-Union{Tuple{T}, Tuple{Rule{T}, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.can_match","text":"Returns nothing if the match is acceptable for rewriting according to the rule, otherwise returns the reason why it should be rejected\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.freevars-Union{Tuple{T}, Tuple{Rule{T}, Symbol}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.freevars","text":"Get a list of AttrVar indices which are NOT bound by the I→R morphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map-Union{Tuple{T}, Tuple{Rule{T}, Any, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map","text":"Don't bind variables for things that are not ACSets\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map-Union{Tuple{T}, Tuple{Rule{T}, Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map","text":"Given the match morphism and the result, construct a map X → X′ which binds any free variables introduced into the result.\n\nL <- I -> R m ↓ ↓ ↓ res G <- • -> X ↓ X′\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_match-Tuple","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_match","text":"Get one match (if any exist) otherwise return \n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_matches-Union{Tuple{T}, Tuple{Rule{T}, ACSets.ACSetInterface.ACSet}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_matches","text":"Get list of possible matches based on the constraints of the rule\n\nThis function has the same behavior as the generic get_matches, but it is more performant because we do not have to query all homomorphisms before finding a valid match, in case n=1. \n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_matches-Union{Tuple{T}, Tuple{Rule{T}, Any}} where T","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_matches","text":"If not rewriting ACSets, we have to compute entire Hom(L,G).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_pmap-Tuple{Symbol, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_pmap","text":"Extract the partial map (derived rule) from full output data\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_rmap-Tuple{Symbol, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_rmap","text":"Extract the map from the R to the result from the full output data\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite-Tuple{AlgebraicRewriting.Rewrite.Utils.AbsRule, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite","text":"rewrite(r::Rule, G; kw...)\n\nPerform a rewrite (automatically finding an arbitrary match) and return result.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match-Tuple{AlgebraicRewriting.Rewrite.Utils.AbsRule, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match","text":"rewrite_match(r::Rule, m; kw...)\n\nPerform a rewrite (with a supplied match morphism) and return result.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs-Tuple{Rule{:DPO}, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs","text":"Further induced equations between AttrVars, given a specific match morphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs-Tuple{Rule{:DPO}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs","text":"Ignore for other categories\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs-Tuple{Rule{:DPO}, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.check_match_var_eqs","text":"A match may be invalid because two variables (which are to be assigned different values via the I -> R map) are identified (due to merging via the I->L map, which morally ought be monic but is not for AttrVars). We can check this before computing the pushout to make sure that we will not get an inconsistent result when trying to compute it. This requires executing the custom exprs of the rewrite rule, so we may wish to build in the ability to skip this step if that is computationally intensive.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{Rule{:DPO}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":"rewrite_match_maps(r::Rule{:DPO}, m)\n\nApply a DPO rewrite rule (given as a span, L<-I->R) to a ACSet using a match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H\n\nThis works for any type that implements pushout_complement and pushout\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{Rule{:CoNeg}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":"rewrite_match_maps(r::Rule{:CoNeg}, m)\n\nApply a CoNegation rewrite rule (given as a span, L↩I->R) to a ACSet using a monic match morphism m which indicates where to apply the rewrite. l r L <- I -> R m ↓ ↓ ↓ G <- K -> H where K = ~L ∨ I\n\nThis works for any type that implements bi-Heyting logic operators ~ and ∨.\n\nThis is described here. Essentially, it is partway between DPO and SPO. Suppose the rule tries to delete two things, one of which satisfies the dangling condition, the other violates it. While DPO would fail to apply at all, and SPO would delete both things (cascading the deletion for the latter), co-negation rewriting would simply delete the item which can be deleted without cascading and ignore the other element.\n\nIt includes a quote which indicates that this method should work even when the match morphism isn't monic, if it satisfies the identification condition. Supporting this is not yet implemented.\n\nMatch morphisms which bind attribute variables are not monic, hence we this form of rewriting doesn't support VarACSets. Intuitively, it feels like this restriction could be relaxed.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.SPO.partial_pushout-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.SPO.partial_pushout","text":"C ← Ag ↪ A ↩ Af → B \n\nA ↩ f∇g → Bgf ↪ B ↓ ⌜ ↓ C ↩ Cfg -> D\n\nImplementation of Construction 6 in Löwe's \"Algebraic approach to SPO graph transformation\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.SqPO.final_pullback_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{Ob, Hom} where {Ob, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.SqPO.final_pullback_complement","text":"See Theorem 2 of 'Concurrency Theorems for Non-linear Rewriting Theories' f B <–- A m ↓ ↓ n C <– D g\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{Rule{:SqPO}, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":"rewrite_match_maps(r::Rule{:SqPO},m; pres::Union{Nothing, Presentation}=nothing)\n\nSesqui-pushout is just like DPO, except we use a final pullback complement instead of a pushout complement.\n\nr.L r.R\n\nL <-⌞K -> R m ↓ ↓k ↓ r I <- • ->⌜O i o\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.PBPO.PBPORule","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.PBPO.PBPORule","text":" l r\n\nL ⟵ K ⟶ R tl ↓ ↓ tk <== tl, tk must be monic L' ⟵ K'\n\nIt is assumed we never want the typing/adherence match to be monic, but we can optionally restrict the match L → G to be monic.\n\nWe can attach application conditions to both the match morphism as well as the adherence morphism. Until morphism search under constraints becomes efficient, it's sometimes needed to just directly state the adherence morphism as a function of the match morphism.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Rewrite.PBPO.canon-NTuple{5, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.PBPO.canon","text":"Take a PBPO rule and put into normal form, i.e. where the lower square forms a pullback\n\nSee Prop 2.4 of \"The PBPO graph transformation approach\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.PBPO.partial_abstract-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.PBPO.partial_abstract","text":"This construction addresses the following problem: ideally when we 'abstract' an ACSet from X to A->X, maps into X, say B->X, can be canonically pulled back to maps B->A which commute. However, A won't do here, because there may not even exist any maps B->A. If B has concrete attributes, then those cannot be sent to an AttrVar in A. Furthermore, if B has multiple 'references' to an AttrVar (two different edges, each with AttrVar(1), sent to two different edges with the same atttribute value in X), then there is no longer a canonical place to send AttrVar(1) to in A, as there is a distinct AttrVar for every single part+attr in X. So we need a construction which does two things to A->X, starting with a map B->X. 1.) replaces exactly the variables we need with concrete values in order to allow a map B->A, 2.) quotients variables in A so that there is exactly one choice for where to send attrvars in B such that the triangle commutes.\n\nStarting with a map L -> G (where G has no AttrVars), we want the analogous map into a \"partially abstracted\" version of G that has concrete attributes replaced with AttrVars EXCEPT for those attributes which are mapped to by concrete attributes of L. Likewise, multiple occurences of the same variable in L correspond to AttrVars which should be merged in the partially-abstracted G.\n\nFor example, for a schema with a single Ob and Attr (where all combinatorial maps are just {1↦1, 2↦2}):\n\nL = [AttrVar(1), :foo]\nG = [:bar, :foo, :baz]\nabs(G) = [AttrVar(1), AttrVar(2), AttrVar(3)]\nexpected result: [AttrVar(1), :foo, AttrVar(2)]\nL -> Partial_abs(G) ↓ ↑ G <- abs(G)\n\nThis function computes the top arrow of this diagram starting with the left arrow. The bottom arrow is computed by abstract_attributes and the right arrow by sub_vars. Furthermore, a map from Partial_abs(G) to G is provided.\n\nThis is the factorization system arising from a coreflective subcategory.\n\n(see https://ncatlab.org/nlab/show/reflective+factorization+system and https://blog.algebraicjulia.org/post/2023/06/varacsets/)\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map-Tuple{PBPORule, Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_expr_binding_map","text":"Use exprs and k_exprs to fill in variables introduced by applying the rw rule.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.get_matches-Tuple{PBPORule, ACSets.ACSetInterface.ACSet}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.get_matches","text":"PBPO matches consist of two morphisms. First, a match m: L → G, and secondly a typing G → L′. With attributes, it is not so simple because G has concrete values for attributes and L′ may have variables. Therefore, we actually change the typing to map out of A, an abstracted version of G (with its attributes replaced by variables). So we lift matches L->G to matches L->A, then search α∈Hom(A,L′).\n\nIn general, we want α to be uniquely determined by m, so by default α_unique is set to true.\n\n m\n\nL⌟ ⟶ G || ↓ α L ⟶ L′ tl\n\n m\n\nL ⟶ G tl ↓ ↘a ↑ (abs = partial abstraction. Note a is Labs in the code.) L′⟵ A α\n\nThe \"strong match\" condition we enforce is that: tl⁻¹(α(A)) = a⁻¹(A). This means we can deduce precisely what m is by looking at α.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps-Tuple{PBPORule, Any}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Utils.rewrite_match_maps","text":" r\n K ----> R\ngₗ u ↓ gᵣ ⌜ ↓ w\n\nGₗ <–– Gk ––> Gᵣ α ↓ ⌞ ↓ u' L′ <– K′ tₗ\n\nFor the adherence morphism α to be valid, it must satisfy a condition with m, tₗ. This is checked for matches provided by get_matches, so by default we do not check it.\n\nL <–⌞• m ↓ ↓ G ⟵ Gk\n\nSee Lemma 7.2 of \"TERMINATION OF GRAPH TRANSFORMATION SYSTEMS USING WEIGHTED SUBGRAPH COUNTING\" by Overbeek and Endrullis (2023)\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Rewrite.Migration.pres_hash-Tuple{GATlab.Models.Presentations.Presentation}","page":"Library Reference","title":"AlgebraicRewriting.Rewrite.Migration.pres_hash","text":"Want a filename that is stable to multiple Julia sessions but changes when the schema changes. This minimizes the need to clear the cache.\n\n\n\n\n\n","category":"method"},{"location":"api/#Schedules","page":"Library Reference","title":"Schedules","text":"","category":"section"},{"location":"api/","page":"Library Reference","title":"Library Reference","text":"Modules = [\n AlgebraicRewriting.Theories,\n AlgebraicRewriting.Poly,\n AlgebraicRewriting.Wiring,\n AlgebraicRewriting.Eval,\n AlgebraicRewriting.Basic,\n AlgebraicRewriting.Conditionals,\n AlgebraicRewriting.RuleApps,\n AlgebraicRewriting.Queries,\n AlgebraicRewriting.Visuals\n]","category":"page"},{"location":"api/#AlgebraicRewriting.Schedules.Poly","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly","text":"Mealy machines (augmented with monadic output) are a user-friendly format for specifying a behavior tree. Behavior trees in general are not finitely expressible, but we focus on trees which can be lazily generated by functions.\n\nAlthough it is conceptually simple to think of a single set of \"input doors\" out \"output doors\" to enter/leave the Mealy machine, such that a Mealy machine has type A → B, we use Σᵢ Aᵢ → Σⱼ Bⱼ, where Aᵢ and Bⱼ are Julia types. This allows us to represent a Mealy machine with (Int + String)-many input doors, for example.\n\n\n\n\n\n","category":"module"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.List","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.List","text":"\"The list monad returns the set of packages labeled with a natural number N, each of which has N-many slots.\"\n\n\n\n\n\n","category":"constant"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.Maybe","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.Maybe","text":"\"The Maybe monad, y+1, consists of two packages, one with one slot and the other with no slots.\"\n\n\n\n\n\n","category":"constant"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.BTree","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.BTree","text":"Lazily grown behavior tree induced by a Mealy machine. The future behavior is dictated by the inputs seen thus far (i.e. a vector of WireVals).\n\nEach vertex is identified by a sequence of inputs and has a state of the Mealy machine associated with it.\n\nEach nonempty sequence of inputs has a MealyRes associated with it.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.BTree-Tuple{Vector{WireVal}}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.BTree","text":"Grow a tree and return the result.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.Mealy","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.Mealy","text":"A function that maintains a state (initially s0) and has monadic output for some polynomial monad t.\n\nThe function f must be of type S × WireVal → S × (t ◁ WireVal) \n\n (i.e. S × Wireval → MealyRes)\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.MealyRes","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.MealyRes","text":"Output of a Mealy machine\n\nnewS - The new state of the Mealy machine mval - outputs along with their monadic values (e.g. probability weights) msg - A message reporting something about the computation \n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.PMonad","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.PMonad","text":"Quotes in this docstring and others taken from David Spivak: https://topos.site/blog/2023/09/powers-of-polynomial-monads/#exponentiating-monads\n\n\"A polynomial monad is a polynomial functor t with coherent maps η: y → t and μ: t ◁ t → t.\n\nPolynomial monads can be thought of as offering compositional (possibly labeled) packages with some number of slots. The compositionality of this packaging says that (via the monad unit) we know how to package up a given element of any set, and that (via the monad multiplication) we can take a package of packages and simplify it to a single package.\"\n\nWe consider monads t of the form: t = Σ_{i ∈ t(1)} y^{t[i]}\n\nI is the type of labels, e.g. probability weights.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.Simulator","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.Simulator","text":"Equips a wiring diagram description of a simulator with mutable data structures (now behavior trees for each box, but possibly incremental homomorphism caches in the future). Requires that all the boxes of the WiringDiagram be convertable to BTrees.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.TrajStep","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.TrajStep","text":"A trajectory step is a box being fed a particular value\n\nThis only makes sense with reference to a WiringDiagram which box refers to.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.WireVal","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.WireVal","text":"For an in/output, Σᵢ Aᵢ, provide wire index + value on wire\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.add_edge-Union{Tuple{I}, Tuple{Traj{I}, TrajStep{I}}} where I","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.add_edge","text":"Append without mutating\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.apply_schedule-Union{Tuple{I}, Tuple{Simulator, Any}, Tuple{Simulator, Any, PMonad{I}}} where I","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.apply_schedule","text":"In theory applying a schedule should result in a list of ACSets associated with out ports and monad labels (e.g. probabilities), and if one were to want to recover the trajectory of the output one would have to use a Writer monad of some sort. For simplicity, the application of a schedule will simply return the trajectories themselves (monadic multiplication could in principle condense this output to the pure output).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.apply_traj_step-Tuple{Simulator, Traj, Catlab.WiringDiagrams.DirectedWiringDiagrams.Wire}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.apply_traj_step","text":"A particular trajectory enters a box. Out of the box comes a list of trajectories.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.curr_state-Tuple{Traj}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.curr_state","text":"Current state of the world\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.currwire-Tuple{Simulator, Traj}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.currwire","text":"Get the wire which the traj is currently on\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.joindist-Tuple{Any}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.joindist","text":"\"The lotteries monad returns the set of packages labeled with a lottery (a natural number N and a probability distribution on it) and again containing N-many slots.\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Poly.joinstr-Tuple{Any}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Poly.joinstr","text":"Writer monad\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate-Tuple{Schedule}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","text":"Map a functor over the data of a schedule\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.AgentBox","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.AgentBox","text":"Type for primitive boxes used in a schedule. These are the generating morphisms of a traced monoidal category, with objects being lists of ACSets.\n\n\n\n\n\n","category":"type"},{"location":"api/#ACSets.DenseACSets.sparsify-Tuple{Schedule}","page":"Library Reference","title":"ACSets.DenseACSets.sparsify","text":"Map sparisfication over the data of a schedule\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.merge_wires","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.merge_wires","text":"The comonoid structure - merging multiple wires into one. This is unproblematic because the world state only ever exists on one wire at a given time.\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.mk_sched-Union{Tuple{T}, Tuple{NamedTuple, NamedTuple, Names{T}, Union{AbstractDict, NamedTuple}, Expr}} where T","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.mk_sched","text":"Make a wiring diagram with ob/hom generators using @program macro\n\nTODO double check that this does not introduce any wire splitting.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.singleton-Tuple{AlgebraicRewriting.Schedules.Wiring.AgentBox}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.singleton","text":"Make a wiring diagram around a box\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.str_hom-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.str_hom","text":"Visualize the data of a CSet homomorphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Wiring.wire_vals-Tuple{Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagram, Int64}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Wiring.wire_vals","text":"1 = inwire, 2 = outwire\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Eval","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Eval","text":"Specialized code for handling rewriting of ACSets with the identity monad\n\n\n\n\n\n","category":"module"},{"location":"api/#AlgebraicRewriting.Schedules.Eval.interpret!-Tuple{Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagram, Catlab.CategoricalAlgebra.CSets.ACSetTransformation{<:ACSets.ACSetInterface.ACSet{<:ACSets.ACSetInterface.MarkAsDeleted}}}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Eval.interpret!","text":"interpret a wiring diagram, with each box updating its state in place\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Eval.interpret-Tuple{Catlab.WiringDiagrams.DirectedWiringDiagrams.WiringDiagram, Catlab.CategoricalAlgebra.CSets.ACSetTransformation{<:ACSets.ACSetInterface.ACSet{<:ACSets.ACSetInterface.MarkAsDeleted}}}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Eval.interpret","text":"Interpret a wiring diagram, recording the trajectory taken\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Basic.Initialize","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Basic.Initialize","text":"A box that spits out a constant ACSet with an empty agent above it. Possibly, it does not take any inputs, so it can act as a comonoid counit.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Basic.Strengthen","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Basic.Strengthen","text":"Adds to both agent and the state of the world via a pushout.\n\n Agent₁ → Agent₂\n ↓ ⇣ \n World₁ -->⌜World₂\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Basic.Weaken","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Basic.Weaken","text":"Change the agent to a subobject of the current agent without changing the world\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.Conditional","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.Conditional","text":"A primitive box in a NestedDWD which does not change the state but redirects it out of one of n wires. \n\nIt contains a function (A->X) -> ℝⁿ. This optionally depends on the internal state. This weights probability for n outports, conditional on the status of an ACSet. If the function just depends on X rather than the whole morphism, withagent is false. If the function does not depend on the internal state (assumed to be true iff initial state is nothing), then withstate is false.\n\nThe state and update function are by default trivial.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.const_cond-Tuple{Vector{Float64}, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.const_cond","text":"Create a branching point with fixed probabilities for each branch\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.for_schedule-Tuple{Schedule, Int64}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.for_schedule","text":"Perform a 1-1 schedule n times\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.if_cond-Tuple{Symbol, Function, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.if_cond","text":"Enter the 1st branch iff the world state evaluates to true\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.uniform-Tuple{Int64, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.uniform","text":"A uniform chance of leaving each of n branches\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Conditionals.while_schedule-Tuple{Schedule, Function}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Conditionals.while_schedule","text":"Perform a 1-1 schedule until a condition is met\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.RuleApps.RuleApp","page":"Library Reference","title":"AlgebraicRewriting.Schedules.RuleApps.RuleApp","text":"Has the semantics of applying the rule to some match that is found (no guarantees on which one, which should be controlled by application conditions). If rewrite occurs, exit mode 1, else exit mode 2.\n\nThe agent is related to the L and R patterns of the rule. This can be done via a Span, or implicitly as a homomorphism into \"I\" of the rewrite rule, and alternatively just from the shape of the agent alone (if it is identical to I, take the id map, otherwise take the unique morphism into I).\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.Schedules.RuleApps.has_match-Tuple{String, AlgebraicRewriting.Rewrite.Utils.AbsRule, ACSets.DenseACSets.StructACSet}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.RuleApps.has_match","text":"A box that takes the first output iff there is a match from a rule into the current state\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.RuleApps.loop_rule-Tuple{RuleApp}","page":"Library Reference","title":"AlgebraicRewriting.Schedules.RuleApps.loop_rule","text":"Feed the \"rewrite applied\" output back into the input of the rule application\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.Schedules.Queries.Query","page":"Library Reference","title":"AlgebraicRewriting.Schedules.Queries.Query","text":"Has an A input/output and a B input/output (by default, the B input can be changed to some other type if needed). \n\nA R ---------↖\n↓ ↓ []\n\n⌜–––-⌝ [] | Query | [agent subroutine] ⌞–––-⌟ [] ↓ ↓ ↓ [] A B ∅ [] ↘–––––-↗ Performs one action per element of Hom(B,X), optionally with some constraints. (i.e. sends you out along the B wire with agent Bₙ->X). \n\nAfter you have done this for all Bₙ, then you exit the A port (you need to update the A->X map, and, if at any point the agent was deleted, then you exit a third door typed by 0).\n\nA constraint optionally will be applied to (1) the A->W<-B cospan of old agent and purported new agent. (the new agent is the first argument to the constraint) \n\n\n\n\n\n","category":"type"},{"location":"api/#CategoricalAlgebra","page":"Library Reference","title":"CategoricalAlgebra","text":"","category":"section"},{"location":"api/","page":"Library Reference","title":"Library Reference","text":"Modules = [\nAlgebraicRewriting.FinSets,\nAlgebraicRewriting.CSets,\nAlgebraicRewriting.StructuredCospans,\nAlgebraicRewriting.PartialMap\n]","category":"page"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.id_condition-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s1\", Hom} where {var\"#s1\"<:(Catlab.CategoricalAlgebra.FinSets.FinSet{Int64}), Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.id_condition","text":"Check identification condition for pushout complement of finite sets.\n\nThe identification condition says that the functions do not map (1) both a deleted item and a preserved item in L to the same item in G or (2) two distinct deleted items to the same item. It is trivially satisfied for injective functions.\n\nReturns pair of iterators of\n\n(1) a nondeleted item that maps to a deleted item in G (2) a pair of distinct items in L that are deleted yet mapped to the same item in G.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s3\", Hom} where {var\"#s3\"<:(Catlab.CategoricalAlgebra.FinSets.FinSet{Int64}), Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"Compute a pushout complement of finite sets, if possible.\n\nGiven functions l I L and m L G to form a pushout square\n\nl\n\nL ← I m ↓ ↓k G ← K g\n\ndefine the set K = G m(L l(I)) and take g K G to be the inclusion. Then the map k I K is determined by the map lm I G from the requirement that the square commutes.\n\nPushout complements exist only if the identification condition is satisfied. An error will be raised if the pushout complement cannot be constructed. To check this in advance, use can_pushout_complement.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.Migrate","text":"TODO: check if functorial\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.cascade_subobj-Tuple{ACSets.ACSetInterface.ACSet, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.cascade_subobj","text":"Recursively delete anything, e.g. deleting a vertex deletes its edge\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.check_pb-NTuple{4, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.check_pb","text":"Y i↘ f_ X → • g_ ↓ ⌟ ↓ f • → • g\n\nCheck whether (X, f,g) is the pullback of (f,g), up to isomorphism (i.e. the pullback of f and g produces (Y,π₁,π₂), where Y is isomorphic to X and i⋅f_ = π₁ & i⋅g_ = π₂.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.fibers-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.fibers","text":"Every morphism induces a partition of the parts of the domain. This function finds every nontrivial partition (size greater than one element) for the objects of the schema.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.gluing_conditions-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s56\", Hom} where {var\"#s56\"<:ACSets.ACSetInterface.ACSet, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.gluing_conditions","text":"Check both id condition and dangling condition\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.invert_hom-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.invert_hom","text":"Invert a morphism which may not be monic nor epic. When the morphism is not monic, an arbitrary element of the preimage is mapped to. When it is not epic, a completely arbitrary element is mapped to.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.invert_iso","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.invert_iso","text":"Invert some (presumed iso) components of an ACSetTransformation (given by s)\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.sub_vars","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.sub_vars","text":"Given a value for each variable, create a morphism X → X′ which applies the substitution. We do this via pushout.\n\nO –> X where C has AttrVars for merge equivalence classes ↓ and O has only AttrVars (sent to concrete values or eq classes C in the map to C.\n\nsubs and merge are dictionaries keyed by attrtype names\n\nsubs values are int-keyed dictionaries indicating binding, e.g. ; subs = (Weight = Dict(1 => 3.20, 5 => 2.32), ...)\n\nmerge values are vectors of vectors indicating equivalence classes, e.g. ; merge = (Weight = [[2,3], [4,6]], ...)\n\n\n\n\n\n","category":"function"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.var_eqs","text":"Further induced equations between AttrVars, given a specific match morphism\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.CSets.var_pullback-Union{Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multicospan{var\"#s64\", Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {var\"#s64\"<:(ACSets.DenseACSets.StructACSet{S, Ts}), Hom}}, Tuple{Ts}, Tuple{S}} where {S, Ts}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.CSets.var_pullback","text":"Take an ACSet pullback combinatorially and freely add variables for all attribute subparts.\n\nThis relies on implementation details of abstract.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.can_pushout_complement-Tuple{Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.can_pushout_complement","text":"Can a pushout complement be constructed for a composable pair?\n\nEven in nice categories, this is not generally possible.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Any, Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"Pushout complement: extend composable pair to a pushout square.\n\nPushout complements are the essential ingredient for double pushout (DPO) rewriting.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s57\", Hom} where {var\"#s57\"<:Catlab.CategoricalAlgebra.SliceCategories.Slice, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"pushout_complement(f::SliceHom, g::SliceHom)\n\nCompute a pushout complement in a slice category by using the pushout complement in the underlying category.\n\n f\n\nB <– A –-⌝ | ↘ ↙ | g| X | f′ ↓ ↗ ↖ cx | D <–- C <– g′\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.ComposablePair{var\"#s57\", var\"#s58\", <:StaticArraysCore.StaticArray{Tuple{2}, var\"#s58\", 1}} where {var\"#s57\"<:ACSets.ACSetInterface.ACSet, var\"#s58\"<:Catlab.CategoricalAlgebra.CSets.TightACSetTransformation}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.FinSets.pushout_complement","text":"Compute pushout complement of attributed C-sets, if possible.\n\nThe pushout complement is constructed pointwise from pushout complements of finite sets. If any of the pointwise identification conditions fail (in FinSet), this method will raise an error. If the dangling condition fails, the resulting C-set will be only partially defined. To check all these conditions in advance, use the function can_pushout_complement.\n\nIn the absence of AttrVars, K is a subobject of G. But we want to be able to change the value of attributes. So any variables in I are not concretized by the I->K map. However, AttrVars may be merged together if m: L -> G merges parts together.\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.CategoricalAlgebra.HomSearch.homomorphisms-Tuple{Catlab.CategoricalAlgebra.SliceCategories.Slice, Catlab.CategoricalAlgebra.SliceCategories.Slice}","page":"Library Reference","title":"Catlab.CategoricalAlgebra.HomSearch.homomorphisms","text":"This could be made more efficient as a constraint during homomorphism finding.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.StructuredMultiCospanHom","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.StructuredMultiCospanHom","text":"A component-wise map between two cospans. The first component given is the apex map, with the following maps being the legs.\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.openrule","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.openrule","text":"A span of StructuredMulticospanHoms, interpreted as a DPO rewrite rule\n\n\n\n\n\n","category":"type"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_-Tuple{openrule, openrule}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_","text":"composeH_(r₁, r₂)\n\ncompose two rewrite rules horizontally (via pushouts) as shown below: L₁₋₍ₙ₋₁₎-> L <- Lₙ X₁ -> X <- X₂₋ₘ L₁₋₍ₙ₋₁₎ -> L +Lₙ X <- X₂₋ₘ ↑ λ ↑ ↑ ↑ ↑ χ ↑ ↑ ↑ ↑ I₁₋₍ₙ₋₁₎-> I <- Iₙ ∘h Y₁ -> Y <- Y₂₋ₘ = I₁₋₍ₙ₋₁₎ -> I +Iₙ Y <- Y₂₋ₘ ↓ ρ ↓ ↓ ↓ ↓ ζ ↓ ↓ ↓ ↓ R₁₋₍ₙ₋₁₎-> R <- Rₙ Z₁ -> Z <- Z₂₋ₘ R₁₋₍ₙ₋₁₎ -> R +Rₙ Z <- Z₂₋ₘ\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_-Union{Tuple{L}, Tuple{Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan{L}, Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospan{L}}} where L","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeH_","text":"Cospan composition given by pushout\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_-Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_","text":"Finset span composition given by pullback\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_-Tuple{openrule, openrule}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.composeV_","text":"composeV_(r₁, r₂)\n\ncompose two rewrite rules vertically with pullbacks, as shown below: L₁₋ₙ -> L ↑ ↑ I₁₋ₙ -> I ↓ ↓ L₁₋ₙ -> L R₁₋ₙ -> R ↑ ↑ ∘v = I₁₋ₙ ×ᵣ₁₋ₙ Θ₁₋ₙ -> I ×ᵣ Θ Λ₁₋ₙ -> Λ ↓ ↓ ↑ ↑ Ω₁₋ₙ -> Ω Θ₁₋ₙ -> Θ ↓ ↓ Ω₁₋ₙ -> Ω\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.id2H_-Union{Tuple{L_}, Tuple{Catlab.CategoricalAlgebra.FreeDiagrams.Multispan{Ob, Hom, <:StaticArraysCore.StaticArray{Tuple{2}, Hom, 1}} where {Ob, Hom}, Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanOb{L_}}} where L_","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.id2H_","text":"Pass dummy value in because a span of invertible FinFunctions does not retain L type\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.idV_-Union{Tuple{Catlab.CategoricalAlgebra.StructuredCospans.StructuredCospanOb{L}}, Tuple{L}} where L","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.idV_","text":"Vertical arrows are spans of invertible finfunctions\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_pushout_complement-Tuple{openrule, StructuredMultiCospanHom}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_pushout_complement","text":"Initial data: 4 structured cospans + 3 cospan morphisms: μ, λ, ρ g G₁₋ₙ –> G ↑ l ↑ μ L₁₋ₙ –> L ↑ i ↑ λ I₁₋ₙ –> I ↓ r ↓ ρ R₁₋ₙ –> R\n\nComputed data: 2 new structured cospans + 4 cospan morphisms: γ, η, ik, rh G₁₋ₙ G ↑ k ↑ γ ik I₁₋ₙ -> K₁₋ₙ –> K <– I ↓ h ↓ η rh R₁₋ₙ -> H₁₋ₙ –> H <– R In the context of the legs of a multicospan, the indices 1-n refer to the n legs of the cospan. In the context of a map of multicospans, there are 1-(n+1) maps, with the first one designating the map of the apexes. Hence it can make sense to have the elements: zip(legs, maps[2:end]) = [(legᵢ, mapᵢ), ...]\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite-Tuple{openrule, StructuredMulticospan}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite","text":"Apply a rewrite rule to a structured multicospan, where a matching cospan homomorphism is found automatically. If multiple matches are found, a particular one can be selected using m_index. Returns nothing if none are found.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite_match-Tuple{openrule, StructuredMultiCospanHom}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.StructuredCospans.open_rewrite_match","text":"Extract the rewritten structured cospan from the induced rewrite rule\n\n\n\n\n\n","category":"method"},{"location":"api/#Catlab.CategoricalAlgebra.HomSearch.homomorphisms-Union{Tuple{L}, Tuple{StructuredMulticospan{L}, StructuredMulticospan{L}}} where L","page":"Library Reference","title":"Catlab.CategoricalAlgebra.HomSearch.homomorphisms","text":"Find homomorphisms between structured cospans. These are constrained to be iso on the legs of the cospans. Solving this w/ homomorphism finding requires a dynamic acset, and the current hack will be replaced once those are available.\n\nA homomorphism backend that uses SAT/SMT would also make this viable to do without hacking.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.check_eqs-Tuple{ACSets.DenseACSets.StructACSet, GATlab.Models.Presentations.Presentation, Symbol, Int64}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.check_eqs","text":"Confirm a C-Set satisfies its equational axioms\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.eval_path-Tuple{ACSets.DenseACSets.StructACSet, Any, Int64}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.eval_path","text":"Take a GATExpr (an id morphism, a generator, or a composite) and evaluate, starting at a particular point.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_eta-Tuple{ACSets.DenseACSets.StructCSet}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_eta","text":"The natural injection from X ⟶ T(X) When evaluated on the terminal object, this gives the subobject classfier.\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_universal_property-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation, Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_classifier_universal_property","text":"A partial function is defined by the following span: m f A ↩ X → B\n\nWe compute ϕ(m,f): A ⟶ T(B) such that the following is a pullback square: f X ⟶ B m ↓ ↓ η(B) A ⟶ T(B) ϕ\n\nEssentially, ϕ sends elements of A to the 'real' values in T(B) when A is in the subobject picked out by X. When A is 'deleted', it picks out the right element of the additional data added by T(B).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_hom-Tuple{Catlab.CategoricalAlgebra.CSets.ACSetTransformation}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_hom","text":"Because the functorial embedding of objects keeps a copy of the original data, what to do with morphisms is just carry them along. Because our implementation adds all of the additional stuff afterwards, index-wise, we can use literally the same data for a morphism lifted from X⟶Y to T(X)⟶T(Y).\n\nHowever, we still need to map the extra stuff in T(X) to the proper extra stuff in T(Y).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_ob-Tuple{ACSets.DenseACSets.StructCSet}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.partial_map_functor_ob","text":"A functor T, playing the role of Maybe in Set, but generalized to C-Sets.\n\nWhen called on the terminal object, this produces the subobject classifier: See Mulry \"Partial map classifiers and cartesian closed categories\" (1994)\n\nThis function specifies what T does on objects. The key properties:\n\nfor all X ∈ Ob(C), η(X):X⟶T(X) is monic. m f ϕ(m,f)\nfor each span A ↩ X → B, there exists a unique morphism A ⟶ T(B) such that (m,f) is the pullback of ϕ(m,f),η(B))\n\nNot only do we add an extra element to each component of the C-Set, but we need to consider the possibility that a component (with n outgoing morphisms) has any combination of the targets of those morphisms deleted (like the subobject classifier, there are different ways for something to be deleted).\n\nFor example, in Graph, an edge can be deleted that goes between any two vertices of the graph. We can't map all deleted edges to the same point in T(E) (if we're going to satisfy that desired property #2), so we need an extra edge in T(E) for every possibility (from V1 to V2, from V1 to V3, ..., from [Deleted] to V1, ..., from V2 to [Deleted], ... from [Deleted] to [Deleted]), where [Deleted] is our name for the extra element added to T(V).\n\n [src] [tgt]\n\nThus, T(E) ≅ |E| + (|V|+1) × (|V|+1).\n\nIn general, T(X) ≅ |X| + ∏ₕ(|T(codom(h))|) for each outgoing morphism h::X⟶Y\n\nthe |X| corresponds to the 'real' elements of X\nthe second term corresponds to the possible ways an X can be deleted.\nThis recursive formula means we require the schema of the C-set to be acyclic otherwise the size is infinite (assumes schema is free).\n\n\n\n\n\n","category":"method"},{"location":"api/#AlgebraicRewriting.CategoricalAlgebra.PartialMap.topo_obs-Tuple{Any}","page":"Library Reference","title":"AlgebraicRewriting.CategoricalAlgebra.PartialMap.topo_obs","text":"Get topological sort of objects of a schema. Fail if cyclic.\n\n\n\n\n\n","category":"method"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"EditURL = \"../../literate/lotka_volterra.jl\"","category":"page"},{"location":"generated/lotka_volterra/#Lotka-Volterra","page":"Lotka Volterra","title":"Lotka Volterra","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"This is a demonstration of a predator-prey agent-based model.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We start with importing some libraries.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"using Catlab, DataMigrations, AlgebraicRewriting\nusing Random, Test\nusing Luxor # optional: makes the sequence of images via `view_traj` at the end\n\nusing Catlab.Graphics.Graphviz: Attributes, Statement, Node\nusing Catlab.Graphics.Graphviz\n\nconst hom = homomorphism\n\nRandom.seed!(123);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Ontology","page":"Lotka Volterra","title":"Ontology","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Defining an ontology is stating what data is required to specify a state of the simulation at some point in time. In AlgebraicJulia, this is done via declaring a Presentation, i.e. a database schema. Objects (Ob, or tables) are types of entities. Homs (Hom, or foreign keys) are functional relationships between the aforementioned entities. AttrTypes are placeholders for Julia types, which are assigned to Ob via attributes (Attr).","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"The schema below extends the schema for directed graphs, which consists in two tables (E and V, for edges and vertices) and two homs (src and tgt, E→V). It says there are two more types of entities, Sheep and Wolf, and they can be thought of as living on the graph due to homs sheep_loc and wolf_loc which assign each of them a vertex.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Furthermore, we want to give these entities some attributes. In this model, wolves and sheep both have \"energy\", given by Eng (a type variable, which we'll later instantiate with Int). Also, grass lives on vertices, and it's represented by an integer. countdown being zero means the grass is ready to eat, whereas a value above zero represents a counter of time the grass needs until it grows back.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"There is also a direction attribute type, and the edges (as well as animals) will be oriented in a particular direction at any point in time.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"@present SchLV <: SchGraph begin\n (Sheep, Wolf)::Ob\n sheep_loc::Hom(Sheep, V); wolf_loc::Hom(Wolf, V)\n\n (Time, Eng)::AttrType\n countdown::Attr(V, Time);\n sheep_eng::Attr(Sheep, Eng); wolf_eng::Attr(Wolf, Eng)\n\n Dir::AttrType\n dir::Attr(E, Dir); sheep_dir::Attr(Sheep, Dir); wolf_dir::Attr(Wolf, Dir)\nend\n\n# efficient ABM rewriting uses BitSetParts rather than DenseParts to allow\n# in-place pushout rewriting, rather than pure/non-mutating pushouts.)\n@acset_type LV_Generic(SchLV, part_type=BitSetParts) <: HasGraph\nconst LV = LV_Generic{Int, Int, Symbol}\n\nto_graphviz(SchLV; prog=\"dot\")","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We can further extend this schema with an additional attribute of (x,y) coordinates for every vertex. This is nice for visualization but is otherwise unnecessary when doing the actual agent-based modeling. So what we will do is build our model with the LV schema and then run our model with the LV′ schema.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"@present SchLV′ <: SchLV begin\n Coord::AttrType\n coord::Attr(V, Coord)\nend\n\n@acset_type LV′_Generic(SchLV′, part_type=BitSetParts) <: HasGraph\nconst LV′ = LV′_Generic{Int, Int, Symbol, Tuple{Int,Int}};\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We will be representing directions as Symbols and encode the geometry via left and right functions. The attribute will only take values :N, :E, :W, or :S.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"import Catlab.CategoricalAlgebra: left, right\n\nfunction right(s::Symbol)\n if s == :N\n return :E\n elseif s == :S\n return :W\n elseif s == :E\n return :S\n elseif s == :W\n return :N\n end\nend\n\nfunction left(s::Symbol)\n if s == :N\n return :W\n elseif s == :S\n return :E\n elseif s == :E\n return :N\n elseif s == :W\n return :S\n end\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Data-migration-functors","page":"Lotka Volterra","title":"Data migration functors","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"The schema LV has a certain symmetry between wolves and sheep, and this symmetry can be used to take instances of the schema (i.e. world states) and swap the wolves and the sheep. This is helpful for avoiding repeating work: there are certain actions that wolves and sheep share, so, by using this data migration, we can define them in terms of sheep and then migrate along F to obtain the analogous actions for wolves.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"F = Migrate(\n Dict(:Sheep => :Wolf, :Wolf => :Sheep),\n Dict([:sheep_loc => :wolf_loc, :wolf_loc => :sheep_loc,\n :sheep_eng => :wolf_eng, :wolf_eng => :sheep_eng, :countdown => :countdown,\n :sheep_dir => :wolf_dir, :wolf_dir => :sheep_dir,]), SchLV, LV);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We ought to be able to take a state of the world (with no coordinate information) and obtain a state of the world with coordinates (the canonical way to do this is to assign \"variables\" for the values of the coordinates).","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"F2 = Migrate(SchLV, LV, SchLV′, LV′; delta=false);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Initializing-and-visualizing-world-states","page":"Lotka Volterra","title":"Initializing and visualizing world states","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"To help us create initial states for simulations, here is a helper function that makes an n × n grid with periodic boundary conditions. Edges in each cardinal direction originate at every point.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"function create_grid(n::Int)\n lv = LV′()\n coords = Dict()\n for i in 0:n-1 # Initialize grass 50% green, 50% uniformly between 0-30\n for j in 0:n-1\n coords[i=>j] = add_part!(lv, :V; countdown=max(0, rand(-30:30)), coord=(i, j))\n end\n end\n for i in 0:n-1\n for j in 0:n-1\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[mod(i + 1, n)=>j], dir=:E)\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[mod(i - 1, n)=>j], dir=:W)\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[i=>mod(j + 1, n)], dir=:N)\n add_part!(lv, :E; src=coords[i=>j], tgt=coords[i=>mod(j - 1, n)], dir=:S)\n end\n end\n lv\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"To initialize a state of the world with sheep and wolves, we also accept parameters which indicate the fraction of spaces that are populated with that animal.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"function initialize(n::Int, sheep::Float64, wolves::Float64)::LV′\n grid = create_grid(n)\n args = [(sheep, :Sheep, :sheep_loc, :sheep_eng, :sheep_dir),\n (wolves, :Wolf, :wolf_loc, :wolf_eng, :wolf_dir)]\n for (n_, name, loc, eng, d) in args\n for _ in 1:round(Int, n_ * n^2)\n dic = Dict([eng => 5, loc => rand(vertices(grid)),\n d => rand([:N, :E, :S, :W])])\n add_part!(grid, name; dic...)\n end\n end\n grid\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Some visualization code below will allow us to see states of the world. Edges are left implicit (we know from how the graphs were constructed that there are edges between every pair of adjacent vertices).","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"supscript_d = Dict(['1' => '¹', '2' => '²', '3' => '³', '4' => '⁴', '5' => '⁵', '6' => '⁶', '7' => '⁷', '8' => '⁸', '9' => '⁹', '0' => '⁰', 'x' => 'ˣ', 'y' => 'ʸ', 'z' => 'ᶻ', 'a' => 'ᵃ', 'b' => 'ᵇ', 'c' => 'ᶜ', 'd' => 'ᵈ'])\nsupscript(x::String) = join([get(supscript_d, c, c) for c in x]); # energy shown in superscript\n\nfunction view_LV(p::ACSetTransformation, pth=tempname(); name=\"G\", title=\"\")\n if nparts(dom(p), :Wolf) == 1\n star = :Wolf => p[:Wolf](1)\n elseif nparts(dom(p), :Sheep) == 1\n star = :Sheep => p[:Sheep](1)\n elseif nparts(dom(p), :V) == 1\n star = :V => p[:V](1)\n else\n star = nothing\n end\n view_LV(codom(p), pth; name=name, title=title, star=star)\nend\n\nfunction view_LV(p::LV′, pth=tempname(); name=\"G\", title=\"\", star=nothing)\n pstr = [\"$(i),$(j)!\" for (i, j) in p[:coord]]\n stmts = Statement[]\n for s in 1:nv(p)\n st = (star == (:V => s)) ? \"*\" : \"\"\n gv = p[s, :countdown]\n col = gv == 0 ? \"lightgreen\" : \"tan\"\n push!(stmts, Node(\"v$s\", Attributes(\n :label => gv == 0 ? \"\" : string(gv) * st,\n :shape => \"circle\",\n :color => col, :pos => pstr[s])))\n end\n d = Dict([:E => (1, 0), :N => (0, 1), :S => (0, -1), :W => (-1, 0),])\n\n args = [(:true, :Wolf, :wolf_loc, :wolf_eng, :wolf_dir),\n (false, :Sheep, :sheep_loc, :sheep_eng, :sheep_dir)]\n\n for (is_wolf, prt, loc, eng, dr) in args\n for w in parts(p, prt)\n st = (star == ((is_wolf ? :Wolf : :Sheep) => w)) ? \"*\" : \"\"\n e = only(incident(p, p[w, loc], :src) ∩ incident(p, p[w, dr], :dir))\n s = src(p, e)\n dx, dy = d[p[e, :dir]]\n (sx, sy) = p[s, :coord]\n\n L, R = 0.25, 0.1\n wx = sx + L * dx + R * rand()\n wy = sy + L * dy + R * rand()\n ID = \"$(is_wolf ? :w : :s)$w\"\n append!(stmts, [Node(ID, Attributes(\n :label => \"$w\" * supscript(\"$(p[w,eng])\") * st,\n :shape => \"square\", :width => \"0.3px\", :height => \"0.3px\", :fixedsize => \"true\",\n :pos => \"$(wx),$(wy)!\", :color => is_wolf ? \"red\" : \"lightblue\"))])\n end\n end\n\n g = Graphviz.Digraph(name, Statement[stmts...]; prog=\"neato\",\n graph_attrs=Attributes(:label => title, :labelloc => \"t\"),\n node_attrs=Attributes(:shape => \"plain\", :style => \"filled\"))\n open(pth, \"w\") do io\n show(io, \"image/svg+xml\", g)\n end\n g\nend\n\ninit = initialize(2, 0.5, 0.5)\nview_LV(init)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Not only can we visualize states of the world, but we can visualize certain states of the world with certain distinguished agents, such as a sheep, wolf, or patch of grass. The way we specify a state of the world (X) with a distinguished sheep (for example) is a morphism S → X, where S is an ACSet with a single sheep in it.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Below we manually construct a generic sheep (in LV, which doesn't have coordinates). We then use the data migration to give it generic coordinates to obtain a generic LV′ sheep. We use this as the domain of a hom that assigns the sheep to Sheep #2 of the world state init from above.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"S = @acset LV begin V=1; Sheep=1; Dir=1; Eng=1; Time=1;\n sheep_loc=1; sheep_dir=[AttrVar(1)]; sheep_eng=[AttrVar(1)]; countdown=[AttrVar(1)]\nend\n\nview_LV(hom(F2(S), init; initial=(Sheep=[2],)))","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"It will be helpful to not have to manually construct \"generic\" world states like above because it's tedious. We want to say \"give me a sheep\" or \"give me a sheep and a wolf that are on the same vertex\" and have it automatically specify the remaining information in the most generic way possible. The @acset_colim macro is perfect for exactly this. In order to use that macro, we need to compute something first with the yoneda_cache function.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"yLV = yoneda_cache(LV; clear=false); # cache=false means reuse cached results\nI = LV() # Empty agent type\nS = @acset_colim yLV begin s::Sheep end # Generic sheep agent\nW = F(S) # Generic wolf agent, obtained via the swapping `F` data migration\nG = @acset_colim yLV begin v::V end # Generic grass agent\nN = Names(Dict(\"W\" => W, \"S\" => S, \"G\" => G, \"\" => I)); # give these ACSets names\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Rules","page":"Lotka Volterra","title":"Rules","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We have finished specifying what makes up a simulation state, and next is to define what sorts of transitions are possible. This is done by declaring rewrite rules. We also will put these rules into little boxes with an incoming wire and two outgoing wires (called a RuleApp), where wires correspond to the successful (resp. unsuccessful) application of the rewrite rule. In the next section we will focus on assembling these miniature wiring diagrams into an overall simulation.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Here we just note that the wires of the simulation must be labeled with an agent. This is because, at all points in time, there is a distinguished agent (i.e. a morphism A → X, where A is an ACSet with a generic something in it, e.g. a generic sheep like above). So when we wrap our rules into the RuleApp boxes, we need to also specify what those distinguished agents are and how they relate to the pattern + replacement of the rewrite rule within the box.","category":"page"},{"location":"generated/lotka_volterra/#Rotating","page":"Lotka Volterra","title":"Rotating","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Our first action that is possible for sheep (and wolves) is rotation. Animals will, with some probability, change their orientation. This is a rewrite rule which only modifies an attribute rather than changing any combinatorial data, so rather than the usual span L ← I → R data required we simply put in a single ACSet along with an expr dictionary which states how attributes change.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"rl = Rule(S; expr=(Dir=[xs -> left(only(xs))],));\nrr = Rule(S; expr=(Dir=[xs -> right(only(xs))],));\n\nsheep_rotate_l = tryrule(RuleApp(:turn_left, rl, S));\nsheep_rotate_r = tryrule(RuleApp(:turn_right, rr, S));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We can imagine executing these rules in sequence","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"seq_sched = (sheep_rotate_l ⋅ sheep_rotate_r);\nview_sched(seq_sched; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"... or in parallel.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"par_sched = (sheep_rotate_l ⊗ sheep_rotate_r);\nview_sched(par_sched; names=N)","category":"page"},{"location":"generated/lotka_volterra/#Test-rotation","page":"Lotka Volterra","title":"Test rotation","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n E=1; Sheep=1; V=2\n src=1; tgt=2; dir=:W; countdown = [0, 0]\n sheep_loc=1; sheep_eng=100; sheep_dir=:N\n end;\n\n expected = copy(ex);\n expected[:sheep_dir] = :W\n @test is_isomorphic(rewrite(rl, ex), expected)\n rewrite!(rl, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Moving-forward","page":"Lotka Volterra","title":"Moving forward","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_fwd_l = @acset_colim yLV begin\n e::E; s::Sheep;\n sheep_loc(s) == src(e);\n dir(e) == sheep_dir(s)\nend\n\ns_fwd_i = @acset_colim yLV begin e::E end\n\ns_fwd_r = @acset_colim yLV begin\n e::E; s::Sheep; sheep_loc(s) == tgt(e); dir(e) == sheep_dir(s)\nend;\n\ns_n = @acset_colim yLV begin\n e::E; s::Sheep;\n sheep_loc(s) == src(e); dir(e) == sheep_dir(s)\n sheep_eng(s) == 0\nend;\n\nsheep_fwd_rule = Rule(\n hom(s_fwd_i, s_fwd_l; monic=true),\n hom(s_fwd_i, s_fwd_r; monic=true),\n ac=[AppCond(hom(s_fwd_l, s_n), false)],\n expr=(Eng=[vs -> only(vs) - 1],))\n;\n\nsheep_fwd = tryrule(RuleApp(:move_fwd, sheep_fwd_rule,\n hom(S, s_fwd_l), hom(S, s_fwd_r)));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Moving-forward-test","page":"Lotka Volterra","title":"Moving forward test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n V=3; E=2; Sheep=1;\n countdown=[0,0,0]\n src=[1,2]; tgt=[2,3]; dir=[:N,:W]\n sheep_loc=1; sheep_dir=:N; sheep_eng = 10\n end\n expected = copy(ex);\n expected[:sheep_loc] = 2\n expected[:sheep_eng] = 9\n @test is_isomorphic(expected, rewrite(sheep_fwd_rule, ex))\n rewrite!(sheep_fwd_rule, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-eat-grass","page":"Lotka Volterra","title":"Sheep eat grass","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_eat_pac = @acset_colim yLV begin s::Sheep; countdown(sheep_loc(s)) == 0 end;\n\nse_rule = Rule(S; expr=(Eng=[vs -> only(vs) + 4], Time=[vs -> 30],),\n ac=[AppCond(hom(S, s_eat_pac))]);\n\nsheep_eat = tryrule(RuleApp(:Sheep_eat, se_rule, S));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-eating-test","page":"Lotka Volterra","title":"Sheep eating test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n E=1; V=2; Sheep=1;\n src=1; tgt=2; dir=:S; countdown=[10, 0]\n sheep_loc = 2; sheep_eng = 3; sheep_dir=:W\n end\n\n expected = copy(ex)\n expected[2,:countdown] = 30\n expected[1,:sheep_eng] = 7\n\n @test is_isomorphic(expected, rewrite(se_rule, ex))\n rewrite!(se_rule, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Wolves-eat-sheep","page":"Lotka Volterra","title":"Wolves eat sheep","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"w_eat_l = @acset_colim yLV begin\n s::Sheep; w::Wolf\n sheep_loc(s) == wolf_loc(w)\nend;\n\nwe_rule = Rule(hom(W, w_eat_l), id(W); expr=(Eng=[vs -> vs[2] + 20],));\n\nwolf_eat = tryrule(RuleApp(:Wolf_eat, we_rule, W));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Wolf-eating-test","page":"Lotka Volterra","title":"Wolf eating test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n Sheep=1; Wolf=1; V=3; E=2;\n src=[1,2]; tgt=[2,3]; countdown=[9,10,11]; dir=[:N,:N];\n sheep_loc=2; sheep_eng=[3]; sheep_dir=[:N]\n wolf_loc=[2]; wolf_eng=[16]; wolf_dir=[:S]\n end\n\n expected = copy(ex)\n expected[1, :wolf_eng] = 36\n rem_part!(expected, :Sheep, 1)\n\n @test is_isomorphic(rewrite(we_rule,ex), expected)\n rewrite!(we_rule, ex)\n @test is_isomorphic(ex,expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-starvation","page":"Lotka Volterra","title":"Sheep starvation","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_die_l = @acset_colim yLV begin s::Sheep; sheep_eng(s) == 0 end;\n\nsheep_die_rule = Rule(hom(G, s_die_l), id(G))\nsheep_starve = (RuleApp(:starve, sheep_die_rule,\n hom(S, s_die_l), create(G))\n ⋅\n (id([I]) ⊗ Weaken(create(S))) ⋅ merge_wires(I));\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Sheep-starvation-test","page":"Lotka Volterra","title":"Sheep starvation test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n V=1; Sheep=1; Wolf=1\n countdown=20;\n sheep_loc=1; sheep_eng=0; sheep_dir=:W\n wolf_loc=1; wolf_eng=10; wolf_dir=:S\n end\n expected = copy(ex)\n rem_part!(expected, :Sheep, 1)\n\n @test is_isomorphic(rewrite(sheep_die_rule,ex), expected)\n rewrite!(sheep_die_rule,ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Reproduction","page":"Lotka Volterra","title":"Reproduction","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"s_reprod_r = @acset_colim yLV begin\n (x, y)::Sheep\n sheep_loc(x) == sheep_loc(y)\nend;\n\nsheep_reprod_rule = Rule(\n hom(G, S),\n hom(G, s_reprod_r);\n expr=(Dir=fill(vs->only(vs) ,2),\n Eng=fill(vs -> round(Int, vs[1] / 2, RoundUp), 2),)\n);\n\nsheep_reprod = RuleApp(:reproduce, sheep_reprod_rule,\n id(S), hom(S, s_reprod_r)) |> tryrule;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Reproduction-test","page":"Lotka Volterra","title":"Reproduction test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin # test\n ex = @acset LV begin\n Sheep=1; Wolf=1; V=2;\n countdown=[20,30]\n sheep_loc=1; sheep_eng=10; sheep_dir=:W\n wolf_loc=2; wolf_eng=5; wolf_dir=:N\n end\n\n expected = copy(ex)\n add_part!(expected,:Sheep)\n expected[:sheep_eng] = [5, 5]\n expected[:sheep_loc] = [1, 1]\n expected[:sheep_dir] = [:W, :W]\n\n @test is_isomorphic(rewrite(sheep_reprod_rule,ex),expected)\n rewrite!(sheep_reprod_rule,ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Grass-increments","page":"Lotka Volterra","title":"Grass increments","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"g_inc_n = deepcopy(G)\nset_subpart!(g_inc_n, 1, :countdown, 0)\nrem_part!(g_inc_n, :Time, 1);\n\ng_inc_rule = Rule(id(G), id(G);\n ac=[AppCond(hom(G, g_inc_n), false)],\n expr=(Time=[vs -> only(vs) - 1],));\n\ng_inc = RuleApp(:GrassIncrements, g_inc_rule, G) |> tryrule;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Grass-incrementing-test","page":"Lotka Volterra","title":"Grass incrementing test","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"begin\n ex = @acset LV begin\n Sheep = 1; V = 3; E = 2\n src = [1, 2]; tgt = [2, 3]\n sheep_loc = 2; sheep_eng = [3]; sheep_dir = [:N]\n countdown = [1, 10, 2]; dir = fill(:N, 2)\n end\n expected = @acset LV begin\n Sheep = 1; V = 3; E = 2\n src = [1, 2]; tgt = [2, 3]\n sheep_loc = 2; sheep_eng = [3]; sheep_dir = [:N]\n countdown = [0, 10, 2]; dir = fill(:N, 2)\n end\n @test is_isomorphic(rewrite(g_inc_rule, ex), expected)\n rewrite!(g_inc_rule, ex)\n @test is_isomorphic(ex, expected)\nend;\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Assembling-rules-into-a-recipe","page":"Lotka Volterra","title":"Assembling rules into a recipe","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Now we can assemble our building block transitions into a large wiring diagram characterizing the flow of the overall ABM simulation. In addition to the blue rewrite rule blocks, we have red (probabilistic) control flow blocks and yellow Query blocks.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"general = mk_sched((;), (init=:S,), N, (\n turn=const_cond([1.0, 2.0, 1.0], S; name=:turn),\n maybe=const_cond([0.1, 0.9], S; name=:reprod),\n lft=sheep_rotate_l,\n rght=sheep_rotate_r,\n fwd=sheep_fwd,\n repro=sheep_reprod,\n starve=sheep_starve),\n quote\n out_l, out_str, out_r = turn(init)\n moved = fwd([lft(out_l), out_str, rght(out_r)])\n out_repro, out_no_repro = maybe(moved)\n return starve([repro(out_repro), out_no_repro])\n end);\n\nview_sched(general; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"The above was content common to wolves and sheep. The difference is how they eat.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"sheep = sheep_eat ⋅ general; # executed once per sheep\n\nview_sched(sheep; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"We use the swap data migration functor F to translate the sheep routine into a wolf one so that it can be composed with the wolf eating step.","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"wolf = wolf_eat ⋅ F(general); # executed once per wolf\n\nview_sched(wolf; names=N)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Do all sheep, then all wolves, then all daily operations","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"cycle = (agent(sheep; n=:sheep, ret=I)\n ⋅\n agent(wolf; n=:wolves, ret=I)\n ⋅\n agent(g_inc; n=:grass))\n\nview_sched(cycle; names=N)\n\n#=\nWrap the whole thing in a while loop. Also apply the F2 migration to give\neverything coordinates.\n=#\n\noverall = while_schedule(cycle, curr -> nparts(curr, :Wolf) >= 0) |> F2\n\nview_sched(overall; names=F2(N))","category":"page"},{"location":"generated/lotka_volterra/#Running-the-simulation","page":"Lotka Volterra","title":"Running the simulation","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"X = initialize(3, 0.25, 0.25); # 3 × 3 grid, 2 sheep + wolves\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Encourage something exciting to happen by placing a wolf on top of a sheep","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"X[1, :wolf_loc] = X[1, :sheep_loc]\nX[1, :wolf_dir] = X[1, :sheep_dir]\n\nview_LV(X)","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Run the simulation for 100 steps","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"res = interpret(overall, X; maxstep=100);\nnothing #hide","category":"page"},{"location":"generated/lotka_volterra/#Visualizing-the-results","page":"Lotka Volterra","title":"Visualizing the results","text":"","category":"section"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"Run this line to view the trajectory in the generated traj folder","category":"page"},{"location":"generated/lotka_volterra/","page":"Lotka Volterra","title":"Lotka Volterra","text":"view_traj(overall, res[1:10], view_LV; agent=true, names=F2(N));\nnothing #hide","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"EditURL = \"../../literate/ptg_simple.jl\"","category":"page"},{"location":"generated/ptg_simple/#Slice-Bread","page":"Slice Bread","title":"Slice Bread","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"using PrettyTables\n\nusing Catlab\nusing AlgebraicRewriting","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Create an ontology by defining a finite presentation of a freely generated category using @present macro","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"About the world: The Bread World Ontology has the types Thing, BreadLoaf, Countertop, and Stool. The Breadloaf, Countertop, and Stool types have morphisms to Thing that represent is-a relationships. The InOn type can be used to encode a set relation (as opposed to a function) that was two morphisms going to Thing. One morphism points out the LHS of the relation and the other morphism point out the RHS of the relation.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"@present OntBreadWorld(FreeSchema) begin\n Thing::Ob\n BreadLoaf::Ob\n Countertop::Ob\n Stool::Ob\n\n BreadLoafIsThing::Hom(BreadLoaf, Thing) # is-a\n CountertopIsThing::Hom(Countertop, Thing) # is-a\n StoolIsThing::Hom(Stool, Thing) # is-a\n\n InOn::Ob\n inOn_l::Hom(InOn, Thing)\n inOn_r::Hom(InOn, Thing)\nend","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Visualize the ontology","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"to_graphviz(OntBreadWorld)","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Make the ontology an acset type","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"@acset_type BreadWorld(OntBreadWorld)","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Construct rule by defining a span in the category of ACSets","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Use the @acset macro to define an ACSet functor. The LHS refers to a type (or object) in our ontology and the RHS defines the set assignment using FinFunctions. For this, you need to completely specify the ACSet functor, i.e. every object and morphism in the index category must be specified.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"About the rule: This rule moves a breadloaf from a countertop to a stool.","category":"page"},{"location":"generated/ptg_simple/#Left-ACSet","page":"Slice Bread","title":"Left ACSet","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"L = @acset BreadWorld begin\n Thing = 3\n BreadLoaf = 1\n Countertop = 1\n Stool = 1\n\n BreadLoafIsThing = [1]\n CountertopIsThing = [2]\n StoolIsThing = [3]\n\n InOn = 1\n inOn_l = [1]\n inOn_r = [2] # breadloaf is on the countertop\nend","category":"page"},{"location":"generated/ptg_simple/#Middle/Keep-ACSet","page":"Slice Bread","title":"Middle/Keep ACSet","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"The Thing, Breadloaf, Countertop, and Stool types should be held constant. The InOn type will change because we are changing the underlying set function.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"K = @acset BreadWorld begin\n Thing = 3\n BreadLoaf = 1\n Countertop = 1\n Stool = 1\n BreadLoafIsThing = [1]\n CountertopIsThing = [2]\n StoolIsThing = [3]\nend","category":"page"},{"location":"generated/ptg_simple/#Right-ACSet","page":"Slice Bread","title":"Right ACSet","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"R = @acset BreadWorld begin\n Thing = 3\n BreadLoaf = 1\n Countertop = 1\n Stool = 1\n\n BreadLoafIsThing = [1]\n CountertopIsThing = [2]\n StoolIsThing = [3]\n\n InOn = 1\n inOn_l = [1]\n inOn_r = [3] # breadloaf is on the stool\nend","category":"page"},{"location":"generated/ptg_simple/#Left-leg-of-span","page":"Slice Bread","title":"Left leg of span","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"l = ACSetTransformation(K, L, Thing=[1, 2, 3], BreadLoaf=[1], Countertop=[1], Stool=[1])","category":"page"},{"location":"generated/ptg_simple/#Right-leg-of-span","page":"Slice Bread","title":"Right leg of span","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"r = ACSetTransformation(K, R, Thing=[1, 2, 3], BreadLoaf=[1], Countertop=[1], Stool=[1])","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Use AlgebraicRewriting.Rule wrapper to add a rule interface","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"moveBreadRule = Rule(l, r)","category":"page"},{"location":"generated/ptg_simple/#WORLD-STATE","page":"Slice Bread","title":"WORLD STATE","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Define a world state using the @acset macro. This is the ACSet way of specifying an ACSet. For this, you need to completely specify the ACSet functor, i.e. every object and morphism in the index category must be specified. The ACSets must be specified in terms of FinFunctions.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"About the world state: In this world state, there are two countertops, one stool, and one breadloaf. All of these amount to four things. The breadloaf is on the first countertop.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"state = @acset BreadWorld begin\n Thing = 4\n BreadLoaf = 1\n Countertop = 2\n Stool = 1\n\n BreadLoafIsThing = [1]\n CountertopIsThing = [2, 3] # there are two countertops\n StoolIsThing = [4]\n\n InOn = 1\n inOn_l = [1] # breadloaf is on the countertop 1\n inOn_r = [2]\nend","category":"page"},{"location":"generated/ptg_simple/#Apply-Rule","page":"Slice Bread","title":"Apply Rule","text":"","category":"section"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Use the AlgebraicRewriting.get_matches(::Rule{T}, ::ACSet) utility function to find matches between the rule and the state.","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"matches = get_matches(moveBreadRule, state)","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Take the first match","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"match = matches[1]","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"Compute the new world state after rewriting","category":"page"},{"location":"generated/ptg_simple/","page":"Slice Bread","title":"Slice Bread","text":"new_state = rewrite_match(moveBreadRule, match)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"EditURL = \"../../literate/full_demo.jl\"","category":"page"},{"location":"generated/full_demo/#Full-Demo","page":"Full Demo","title":"Full Demo","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"using AlgebraicRewriting, Catlab, AlgebraicPetri, DataMigrations\nusing Test","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"This is a self-contained walkthrough of the main features of AlgebraicRewriting. This is a regular julia file that can be run interactively.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Importantly:","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"use Julia 1.10\nactivate the environment in AlgebraicRewriting.jl/docs\ncheck that graphviz is installed locally (test via \"which dot\" in terminal)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Table of contents:","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"DPO\nSPO\nSqPO\nPBPO+\nGeneralizing graphs: C-Sets, Slices, etc.\nApplication conditions\nAttribute variables\nGraph processes\nGeneral purpose programming / agent-based modeling","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"a. Rewrite and Control Flow boxes b. Agents and Query boxes c. Data migration d. Monadic output","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"The VS Code REPL makes it easy to have figures automatically pop up in a side window, so this is the preferred way of interacting with this file. However, if that is not available, your options are to 1.) copy-paste the code into a Jupyter notebook 2.) use the following to_svg function, which will write a graphviz output to a SVG file and can be viewed in a browser. The Julia pipe syntax |> allows you to easily append \" |> to_svg \" to a line with a visualization.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"to_svg(G, filename=\"tmp.svg\") =\n open(filename, \"w\") do io\n show(io, \"image/svg+xml\", G)\n end\n\nto_graphviz(path_graph(Graph, 3))","category":"page"},{"location":"generated/full_demo/#1.-DPO","page":"Full Demo","title":"1. DPO","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We construct a rule by providing a span, L ← I → R","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L = path_graph(Graph, 2) # • → •\nI = Graph(1) # •\nR = @acset Graph begin\n V = 1\n E = 1\n src = 1\n tgt = 1\nend # •↺\nl = ACSetTransformation(I, L; V=[1]) # graph homomorphism data\nr = ACSetTransformation(I, R; V=[1])\nrule = Rule(l, r)\n\nG = path_graph(Graph, 5) # • → • → • → • → •\nm = only(get_matches(rule, G)) # only one match which satisfies dangling condition","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Provided a specific match (m), we can use the rule to rewrite the graph (G) using rewrite_match(rule, m).","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"res = rewrite_match(rule, m) # • → • → • → •↺\nto_graphviz(res; node_labels=true)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Note that C-Sets are morally regarded up to isomorphism - in particular, limits and colimits may modify the orderings of edges/vertices","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"expected = @acset Graph begin\n V = 4\n E = 4\n src = [1, 2, 3, 4]\n tgt = [2, 3, 4, 4]\nend\n@test is_isomorphic(expected, res)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can also specify the rule via a colimit-of-representables (i.e. generators and relations) syntax. As your schema gets bigger, this becomes more and more convenient. Assigning temporary tags, e.g. e, v, eᵣ to the C-Set elements can also be helpful.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"yG = yoneda_cache(Graph, clear=true); # compute representables\n\nrule2 = Rule(@migration(SchRulel, SchGraph, begin\n L => @join begin\n e::E\n end\n K => @join begin\n v::V\n end\n R => @join begin\n eᵣ::E\n src(eᵣ) == tgt(eᵣ)\n end\n l => begin\n v => src(e)\n end\n end), yG)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can also rewrite without a match (and let it pick an arbitrary match).","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"@test res == rewrite(rule, G)","category":"page"},{"location":"generated/full_demo/#2.-SPO","page":"Full Demo","title":"2. SPO","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rules are by default DPO, but if we specify a type parameter we can change the semantics","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"rule_spo = Rule{:SPO}(l, r) # (same data as before)\n\n@test length(get_matches(rule_spo, G)) == 4 # there are now four matches\nres = rewrite(rule_spo, G)\nto_graphviz(res)\n@test is_isomorphic(res, path_graph(Graph, 3) ⊕ R)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Note: ⊕ and ⊗ are shorthand for (co)products Tip: Julia lets you easily write unicode symbols via \"\\\" followed by a LaTeX name, then hit \"Tab\" to convert the symbol","category":"page"},{"location":"generated/full_demo/#3.-SqPO","page":"Full Demo","title":"3. SqPO","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"If we duplicate a vertex with an incident edge, it will duplicate the edge","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L = Graph(1)\nI = Graph(2)\nR = path_graph(Graph, 2)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can use automated homomorphism search to reduce the tedium of specifying data manually. In this case, there is a unique option.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"l = homomorphism(I, L)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"There are many constraints we can put on the search, such as being monic.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"r = homomorphism(I, R; monic=true)\n\nrule_sqpo = Rule{:SqPO}(l, r) # same data as before)\n\n\nG = star_graph(Graph, 6) # a 5-pointed star\nto_graphviz(G; prog=\"neato\") # changing \"prog\" can sometimes make it look better\n\nm = ACSetTransformation(Graph(1), G; V=[6]) # point at the center\nres = rewrite_match(rule_sqpo, m)\nto_graphviz(res; prog=\"neato\")","category":"page"},{"location":"generated/full_demo/#4.-PBPO","page":"Full Demo","title":"4. PBPO+","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"PBPO+ requires not merely a span but also additional data for L and K which can be thought of as type graphs. The graph G that we rewrite will be typed over the L' type graph to determine how it is rewritten.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L = Graph(1)\nK = Graph(2)\nl = homomorphism(K, L)\nr = id(K)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We allow edges into and out of the matched vertex as well as edges between the vertices incident to the matched vertex","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L′ = @acset Graph begin\n V = 3\n E = 6\n src = [1, 1, 1, 2, 3, 3]\n tgt = [1, 2, 3, 3, 3, 1]\nend\ntl = ACSetTransformation(L, L′; V=[2]) # 2 is the matched vertex\nto_graphviz(L′; node_labels=true)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"The outneighbors of the matched vertex are duplicated (an edge connects the old ones to the new ones) and the matched vertex is duplicated. The new copy of the matched vertex points at the new ones. It does not have any inneighbors.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"K′ = @acset Graph begin\n V = 5\n E = 9\n src = [1, 1, 1, 2, 3, 3, 3, 4, 5]\n tgt = [1, 2, 3, 3, 3, 1, 5, 5, 5]\nend\ntk = ACSetTransformation(K, K′; V=[2, 4])\nto_graphviz(K′; node_labels=true)\n\nl′ = homomorphism(K′, L′; initial=(V=[1, 2, 3, 2, 3],))\n\nprule = PBPORule(l, r, tl, tk, l′)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Apply to an example vertex (#3) with two inneighbors and one outneighbor.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"G = @acset Graph begin\n V = 4\n E = 5\n src = [1, 1, 2, 3, 4]\n tgt = [2, 3, 3, 4, 4]\nend\nto_graphviz(G; node_labels=true)\n\nm = get_match(prule, G; initial=(V=[3],) => Dict())\n\nres = rewrite_match(prule, m)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"V1 is copied to V2. Outneighbor V5 (w/ loop) is copied to V6, creating an edge","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"to_graphviz(res; node_labels=true)","category":"page"},{"location":"generated/full_demo/#5.-Generalizing-Graphs","page":"Full Demo","title":"5. Generalizing Graphs","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Any data structure which implements the required functions we need can, in principle, be used for rewriting. Importantly this includes pushout_complement, pushout, and homomorphism search. These are all implemented generically for any C-Set schema (allowing us to rewrite Petri nets, Semisimplicial sets, etc.)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Here we'll do rewriting in graphs sliced over •⇆•, which is isomorphic to the category of (whole-grain) Petri nets, with States and Transitions.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"function graph_slice(s::Slice)\n h = s.slice\n V, E = collect.([h[:V], h[:E]])\n g = dom(h)\n (S, T), (I, O) = [[findall(==(i), X) for i in 1:2] for X in [V, E]]\n nS, nT, nI, nO = length.([S, T, I, O])\n findS, findT = [x -> findfirst(==(x), X) for X in [S, T]]\n to_graphviz(@acset AlgebraicPetri.PetriNet begin\n S = nS\n T = nT\n I = nI\n O = nO\n is = findS.(g[I, :src])\n it = findT.(g[I, :tgt])\n ot = findT.(g[O, :src])\n os = findS.(g[O, :tgt])\n end)\nend;\nnothing #hide","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"This is the graph we are slicing over.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"two = @acset Graph begin\n V = 2\n E = 2\n src = [1, 2]\n tgt = [2, 1]\nend","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Define a rule which deletes a [T] -> S edge","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"L_ = path_graph(Graph, 2)\nL = Slice(ACSetTransformation(L_, two, V=[2, 1], E=[2])) # [T] ⟶ (S)\ngraph_slice(L)\n\nI_ = Graph(1)\nI = Slice(ACSetTransformation(I_, two, V=[2])) # [T]\nR_ = Graph(2)\nR = Slice(ACSetTransformation(R_, two, V=[2, 1])) # [T] (S)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Using homomorphism search in the slice category","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"rule = Rule(homomorphism(I, L), homomorphism(I, R))\n\nG_ = path_graph(Graph, 3)\nG = Slice(ACSetTransformation(G_, two, V=[1, 2, 1], E=[1, 2])) # (S) ⟶ [T] ⟶ (S)\ngraph_slice(G)\n\nres = rewrite(rule, G) # (S) ⟶ [T] (S)\ngraph_slice(res)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"While the vast majority of functionality is focused on ACSets at the present moment, but there is nothing in principle which limits this.","category":"page"},{"location":"generated/full_demo/#6.-Application-conditions","page":"Full Demo","title":"6. Application conditions","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can construct commutative diagrams with certain edges left unspecified or marked with ∀ or ∃. If only one edge is left free, we can treat the diagram as a boolean function which tests whether the morphism makes the specified paths commute (or not commute). This generalizes positive/negative application conditions and lifting conditions, but because those are most common there are constructors AppCond and LiftCond to make these directly.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":" ∀","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"[↻•] → ? ↓ ↗ ∃ ↓ [↻•⟶•] → [↻•⟶•⟵•↺]","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Every vertex with a loop also has a map to the vertex marked by the bottom map.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"t = terminal(Graph) |> apex\nlooparr = @acset_colim yG begin\n (e1, e2)::E\n src(e1) == tgt(e1)\n src(e1) == src(e2)\nend\n\nv = homomorphism(t, looparr)\nloop_csp = @acset Graph begin\n V = 3\n E = 4\n src = [1, 3, 1, 3]\n tgt = [1, 3, 2, 2]\nend\nb = homomorphism(looparr, loop_csp; monic=true)\nconstr = LiftCond(v, b)\n\n@test !apply_constraint(constr, homomorphism(t, loop_csp))\n@test apply_constraint(constr, b)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"We can combining constraints with logical combinators.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"match vertex iff it has 2 or 3 self loops","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"one, two, three, four, five = [@acset(Graph, begin\n V = 1\n E = n\n src = 1\n tgt = 1\nend) for n in 1:5]\n\nc2 = AppCond(homomorphism(Graph(1), two); monic=true) # PAC\nc3 = AppCond(homomorphism(Graph(1), four), false; monic=true) # NAC\nconstr = c2 ⊗ c3 # logical conjunction: 2 ≤ |E| < 4\n\nrule = Rule(id(Graph(1)), id(Graph(1)); ac=[constr])\n\nG = two ⊕ three ⊕ two ⊕ four ⊕ five ⊕ one\n\n@test length(get_matches(rule, G)) == 3","category":"page"},{"location":"generated/full_demo/#7.-Attribute-variables","page":"Full Demo","title":"7. Attribute variables","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Normally ACSet morphisms must match attribute values exactly, i.e. a weighted graph edge of 8.3 can only be mapped to another edge weighted at 8.3. This becomes very restricted, especially when we want to do some simple computations with attribute values (e.g. when merging two edges, add their values together)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"A recent extension of ACSets makes this possible - each attribute type comes equipped with a finite set of \"variables\" which can be mapped to any concrete value (or another variable).","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"yWG = yoneda_cache(WeightedGraph{Int}; clear=true);\nL = @acset_colim yWG begin\n (e1, e2)::E\n src(e1) == src(e2)\n tgt(e1) == tgt(e2)\nend\nI = WeightedGraph{Int}(2)\nR = @acset WeightedGraph{Int} begin\n V = 2\n E = 1\n Weight = 1\n src = 1\n tgt = 2\n weight = [AttrVar(1)]\nend\n\nl = homomorphism(I, L; monic=true)\nr = homomorphism(I, R; monic=true)\nrule = Rule(l, r; monic=[:E], expr=Dict(:Weight => [xs -> xs[1] + xs[2]]))\n\nG = @acset WeightedGraph{Int} begin\n V = 1\n E = 3\n src = 1\n tgt = 1\n weight = [10, 20, 100]\nend\n\n@test rewrite(rule, G) == @acset WeightedGraph{Int} begin\n V = 1\n E = 2\n src = 1\n tgt = 1\n weight = [30, 100]\nend","category":"page"},{"location":"generated/full_demo/#8.-Graph-processes","page":"Full Demo","title":"8. Graph processes","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"A sequence of rewrite applications can be given a poset structure where α ≤ β means that the rule application α needed to occur before β. This is computed via analyzing the colimit of all the partial maps induced by the rewrites.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"using AlgebraicRewriting.Processes: RWStep, find_deps\n\nG0, G1, G2, G3 = Graph.([0, 1, 2, 3])","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Delete a node","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rule1 = Span(create(G1), id(G0));\nnothing #hide","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Merge two nodes","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rule2 = Span(id(G2), homomorphism(G2, G1));\nnothing #hide","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Add a node","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Rule3 = Span(id(G0), create(G1))\n\nR1, R2, R3 = [Rule(l, r) for (l, r) in [Rule1, Rule2, Rule3]]","category":"page"},{"location":"generated/full_demo/#9.-Trajectory","page":"Full Demo","title":"9. Trajectory","text":"","category":"section"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Step 1: add node 3 to G2","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"M1 = create(G2)\nCM1 = ACSetTransformation(G1, G3; V=[3])\nPmap1 = Span(id(G2), ACSetTransformation(G2, G3; V=[1, 2]))\nRS1 = RWStep(Rule3, Pmap1, M1, CM1)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Step 2: merge node 2 and 3 to yield a G2","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"M2 = ACSetTransformation(G2, G3; V=[2, 3])\nCM2 = ACSetTransformation(G1, G2; V=[2])\nPmap2 = Span(id(G3), ACSetTransformation(G3, G2; V=[1, 2, 2]))\nRS2 = RWStep(Rule2, Pmap2, M2, CM2)","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Step 3: delete vertex 1","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"M3 = ACSetTransformation(G1, G2; V=[1])\nCM3 = create(G1)\nPmap3 = Span(ACSetTransformation(G1, G2; V=[2]), id(G1))\nRS3 = RWStep(Rule1, Pmap3, M3, CM3)\n\n\nsteps = [RS1, RS2, RS3]\n\ng = find_deps(steps)\nto_graphviz(g; node_labels=true)\n\nexpected = @acset Graph begin\n V = 3\n E = 1\n src = 1\n tgt = 2\nend\n@test expected == g","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"Interface that just uses rules and match morphisms: The matches needed to be updated to reflect the particular isomorph that DPO rewriting produces when applying the rule.","category":"page"},{"location":"generated/full_demo/","page":"Full Demo","title":"Full Demo","text":"σ₂ = ACSetTransformation(G2, G2; V=[2, 1])\nσ₃ = ACSetTransformation(G3, G3; V=[3, 1, 2])\n\ng′ = find_deps([R3 => M1, R2 => M2 ⋅ σ₃, R1 => M3 ⋅ σ₂])\n@test g′ == g","category":"page"},{"location":"#AlgebraicRewriting.jl","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"CurrentModule = AlgebraicRewriting","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Algebraic rewriting is a context-aware find-and-replace operation that is useful for maintaining structure in various scenarios. This package provides tools for such operations in Julia, ensuring that rewrite rules adhere to structures defined using ACSets (see ACSets.jl and Catlab.jl). This documentation provides a basic guide to using the AlgebraicRewriting package in Julia. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This page will provide you with a gentle overview of how to design and apply rewrite rules for a simple ACSet. More sophisticated examples can be found in the side-bar.","category":"page"},{"location":"#Setup-Environment","page":"AlgebraicRewriting.jl","title":"Setup Environment","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To begin, set up your environment by importing necessary packages.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"using Catlab\nusing AlgebraicRewriting\nusing DataMigrations","category":"page"},{"location":"#Design-a-rewrite-rule","page":"AlgebraicRewriting.jl","title":"Design a rewrite rule","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"The general process for designing a rewrite rule is as follows:","category":"page"},{"location":"#1.-Define-your-schema","page":"AlgebraicRewriting.jl","title":"1. Define your schema","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"A schema defined by a finite presentation of a generalized algebraic theory model using generators, Ob, Hom, AttrType, and Attr.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"@present SchSportsTeam(FreeSchema) begin\n Player::Ob\n Team::Ob\n Member::Ob\n IsMember::Hom(Member, Player)\n MemberOf::Hom(Member, Team)\n\n Name::AttrType\n PlayerHasName::Attr(Player, Name)\n TeamHasName::Attr(Team, Name)\nend\nto_graphviz(SchSportsTeam)","category":"page"},{"location":"#2.-Create-the-schema-type","page":"AlgebraicRewriting.jl","title":"2. Create the schema type","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Data for rules are stored in a data structure called an ACSet. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"@acset_type SportsTeam(SchSportsTeam)","category":"page"},{"location":"#3.-Define-rule-parts","page":"AlgebraicRewriting.jl","title":"3. Define rule parts","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"A rewrite rule consists of a span of ACSets (L <-l- K -r-> R), namely three ACSets (L, K, R) and two natural transformations (l, r):","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Left ACSet, L, is the pre-condition for the rule to be applied.\nKeep ACSet, K, is the data for the part of the state that remain consistent when the rule is applied.\nRight ACSet, R, is the effect of the rule.\nLeft transformation, l, embeds K in L.\nRight transformation, r, embed K in R.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To define a rule, all five parts need to be defined. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"It is possible to insert data according to the schema using a static approach or the colimit-of-representables approach.","category":"page"},{"location":"#Static-Instantiation-(@acset)","page":"AlgebraicRewriting.jl","title":"Static Instantiation (@acset)","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the static approach, you must fully specify the ACSet functors and natural transformation. Here is a rule that defines the ACSet statically. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"In this example, the rule swaps players, one from each team. AttrVar.(1:2), or [AttrVar(1), AttrVar(2)], are used as variable placeholders for the names of the players. This allows the rule to be applied independent of player names, as long as two players are specified from opposing teams. Contrastingly, [\"Home\", \"Away\"], are specified explicitly and, therefore, this rule can only be applied to teams whose names are \"Home\" and \"Away\"","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"# Both L and R are the same: two players are members of a Home and Away team\nL = R = @acset SportsTeam{String} begin\n Player = 2; Team = 2; Member = 2; Name = 2\n IsMember = [1, 2]; MemberOf = [1, 2]\n PlayerHasName = AttrVar.(1:2)\n TeamHasName = [\"Home\", \"Away\"]\nend\n# K is missing the Member relation. L <- K removes the two players' memberships\n# and K -> R adds in a new membership relation.\nK = @acset SportsTeam{String} begin\n Player = 2; Team = 2; Name = 2\n PlayerHasName = AttrVar.(1:2)\n TeamHasName = [\"Home\", \"Away\"]\nend\n\n# Manually specify K->L and K->R\n# Important that the player removed from Home (as determined by l: K->L) is \n# assigned (via r: K->R) to the player which is added to away, and vice-versa.\nl = ACSetTransformation(K, L, Player=[1,2], Team=[1, 2], Name=AttrVar.([1,2]))\nr = ACSetTransformation(K, R, Player=[2,1], Team=[1, 2], Name=AttrVar.([2,1])) # swap\n\n# Alternatively we could use automated search, as there are the only two maps \n# K->L (same as K->R because L=R) that do not merge the two players together \nl, r = homomorphisms(K, L; monic=true) # ('monic' = \"no merging allowed\")","category":"page"},{"location":"#Colimit-of-representables-instantiation-(@acset_colim)","page":"AlgebraicRewriting.jl","title":"Colimit-of-representables instantiation (@acset_colim)","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the colimit-of-representables approach, you only need to specify relevant objects and morphism parts. Shown here is the translation of the above rule using @acset_colim.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"ySportsTeam = yoneda(SportsTeam{String})\nL = R = @acset_colim ySportsTeam begin\n (p1, p2)::Player\n (t1, t2)::Team\n (m1, m2)::Member\n IsMember(m1) == p1\n IsMember(m2) == p2\n MemberOf(m1) == t1\n MemberOf(m2) == t2\n TeamHasName(t1) == \"Home\"\n TeamHasName(t2) == \"Away\"\nend # we did not specify PlayerHasName, so it's left generic\nK = @acset_colim ySportsTeam begin\n (t1, t2)::Team\n (p1, p2)::Player\n TeamHasName(t1) == \"Home\"\n TeamHasName(t2) == \"Away\"\nend\nl, r = homomorphisms(K, L; monic=true) # same as above because K,L,R are the same","category":"page"},{"location":"#4.-Construct-the-rule","page":"AlgebraicRewriting.jl","title":"4. Construct the rule","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Use the AlgebraicRewriting.Rule constructor to create the rule. This assumes that a double-pushout (DPO) rewrite rule is being constructed. You may also construct an single-pushout (SPO), sesqui-pushout (SqPO), or pullback-pushout (PBPO) rule.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"rule = Rule{:DPO}(l, r)","category":"page"},{"location":"#Apply-the-rule","page":"AlgebraicRewriting.jl","title":"Apply the rule","text":"","category":"section"},{"location":"#5.-Define-the-initial-state.","page":"AlgebraicRewriting.jl","title":"5. Define the initial state.","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"Similarly, you can choose to define the acset using the static approach or the colimit-of-representable approach.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the static approach, you must fully specify the ACSet for the initial state.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"state = @acset SportsTeam{String} begin\n Player = 4; Member = 4; Team = 2\n IsMember = [1, 2, 3, 4]; MemberOf = [1, 1, 2, 2]\n TeamHasName = [\"Home\", \"Away\"]\n PlayerHasName = [\"Jordan\", \"Alex\", \"Casey\", \"Taylor\"]\nend","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"If using the colimit-of-representable approach, you only need to specify relevant objects and morphism parts.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"state = @acset_colim ySportsTeam begin\n (p1, p2, p3, p4)::Player\n (m1, m2, m3, m4)::Member\n (t1, t2)::Team\n IsMember(m1) == p1; IsMember(m2) == p2; IsMember(m3) == p3; IsMember(m4) == p4\n MemberOf(m1) == t1; MemberOf(m2) == t1; MemberOf(m3) == t2; MemberOf(m4) == t2\n PlayerHasName(p1) == \"Jordan\"\n PlayerHasName(p2) == \"Alex\"\n PlayerHasName(p3) == \"Casey\"\n PlayerHasName(p4) == \"Taylor\"\n TeamHasName(t1) == \"Home\"\n TeamHasName(t2) == \"Away\"\nend","category":"page"},{"location":"#6.-Identify-the-match-from-the-rule-to-the-state","page":"AlgebraicRewriting.jl","title":"6. Identify the match from the rule to the state","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This can be done manually or automatically. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To manually identify the match, fully-specify an ACSet transformation. For this example, we would like to rule to swap p2::Player and p3::Player","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"pattern_match = ACSetTransformation(L, state, Player=[2, 3], Member=[2, 3], \n Team=[1, 2], Name=[\"Alex\", \"Casey\"])","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"To automatically identify the match, use the backtracking search algorithm provided by AlgebraicRewriting. This may return multiple matches, so you can provide logic for deciding which match to select. ","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"pattern_match = homomorphism(L, state; initial=(Name=[\"Alex\", \"Casey\"],))\n\nmatches = get_matches(rule, state)# get all four possible matches, then pick one","category":"page"},{"location":"#7.-Apply-the-rewrite-rule","page":"AlgebraicRewriting.jl","title":"7. Apply the rewrite rule","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This executes the rewrite process using using the defined rule and match.","category":"page"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"result = rewrite_match(rule, pattern_match)","category":"page"},{"location":"#Authors","page":"AlgebraicRewriting.jl","title":"Authors","text":"","category":"section"},{"location":"","page":"AlgebraicRewriting.jl","title":"AlgebraicRewriting.jl","text":"This documentation is maintained by Angeline Aguinaldo and Kristopher Brown.","category":"page"}] }