diff --git a/dev/design.html b/dev/design.html index 7c1c9a6..6f0990e 100644 --- a/dev/design.html +++ b/dev/design.html @@ -64,4 +64,4 @@ @control system control(system) "temperature control"

At each step, the solver will call the function () -> control(system) (a closure is taken at the time when @future is invoked).

Instantious Interactions

You may schedule additional interactions which exist within a single step of the model; such actions are modeled as named tuples (id, priority=0., call). Here, call is a (parameterless) anonymous function.

They exist within a single step of the model and are executed after the calls to _prestep! and _step! finish, in the order of the assigned priorities.

In particular, you may schedule interactions of two kinds:

See poke and @call.

Examples

# `poke`
 poke(agent, 1.) # call `_interact!(agent)`; this call is added to the instantious priority queue with priority 1
# `@call`
 bob_agent = only(getagent(agent, r"bob"))
-@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)` with priority 0
+@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)` with priority 0 diff --git a/dev/design_mmd.html b/dev/design_mmd.html index c2dd6b8..cad7d69 100644 --- a/dev/design_mmd.html +++ b/dev/design_mmd.html @@ -67,4 +67,4 @@ @control system control(system) "temperature control"

At each step, the solver will call the function () -> control(system) (a closure is taken at the time when @future is invoked).

Instantious Interactions

You may schedule additional interactions which exist within a single step of the model; such actions are modeled as named tuples (id, priority=0., call). Here, call is a (parameterless) anonymous function.

They exist within a single step of the model and are executed after the calls to _prestep! and _step! finish, in the order of the assigned priorities.

In particular, you may schedule interactions of two kinds:

See poke and @call.

Examples

# `poke`
 poke(agent, 1.) # call `_interact!(agent)`; this call is added to the instantious priority queue with priority 1
# `@call`
 bob_agent = only(getagent(agent, r"bob"))
-@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)` with priority 0
+@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)` with priority 0 diff --git a/dev/index.html b/dev/index.html index a79118a..be84cd7 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,48 +1,48 @@ -API Documentation · AlgebraicAgents.jl

API Documentation

Agent types

AlgebraicAgents.AbstractAlgebraicAgentType
AbstractAlgebraicAgent

Abstract supertype of all algebraic agents. This is a dynamic structure which parametrizes dynamics of the agent, stores additional data required for the numerical simulation, and optionally logs its state at selected timesteps.

source

Implementing custom types

To implement a custom agent type, you may want to use the convenience macro @aagent which supplies type fields expected (not required, though) by the interface.

Required methods

AlgebraicAgents._step!Method

Step an agent forward (call only if its projected time is equal to the least projected time, among all agents in the hierarchy).

source

Optional methods

Other optional methods include

Loading third-party package integrations

So far, integrations of DifferentialEquations.jl, Agents.jl, and AlgebraicDynamics.jl are provided.

Loading of the integrations is facilitated by Requires.jl; the integration will automatically be included once the respective third-party package is loaded.

For example,

using AlgebraicAgents
+API Documentation · AlgebraicAgents.jl

API Documentation

Agent types

AlgebraicAgents.AbstractAlgebraicAgentType
AbstractAlgebraicAgent

Abstract supertype of all algebraic agents. This is a dynamic structure which parametrizes dynamics of the agent, stores additional data required for the numerical simulation, and optionally logs its state at selected timesteps.

source

Implementing custom types

To implement a custom agent type, you may want to use the convenience macro @aagent which supplies type fields expected (not required, though) by the interface.

Required methods

AlgebraicAgents._step!Method

Step an agent forward (call only if its projected time is equal to the least projected time, among all agents in the hierarchy).

source

Optional methods

Other optional methods include

Loading third-party package integrations

So far, integrations of DifferentialEquations.jl, Agents.jl, and AlgebraicDynamics.jl are provided.

Loading of the integrations is facilitated by Requires.jl; the integration will automatically be included once the respective third-party package is loaded.

For example,

using AlgebraicAgents
 @isdefined DiffEqAgent
true
using AlgebraicAgents, DifferentialEquations
 @isdefined DiffEqAgent
-wrap_system("my_model", ODEProblem((u, p, t) -> 1.01*u, [1/2], (0., 10.)))
agent my_model with uuid fe99bd9e of type DiffEqAgent 
+wrap_system("my_model", ODEProblem((u, p, t) -> 1.01*u, [1/2], (0., 10.)))
agent my_model with uuid 90394c9f of type DiffEqAgent 
    custom properties:
    integrator: 
 t: 0.0
 u: 1-element Vector{Float64}:
- 0.5

For plotting, you will want to load Plots as well. Nevertheless, function draw will inform you when necessary.

Common interface

Agent properties accessors

AlgebraicAgents.setparameters!Function
setparameters!(agent, parameters)

Assign agent's parameters. Parameters are accepted in the form of a dictionary containing path => params pairs.

Examples

setparameters!(agent, Dict("agent1/agent2" => Dict(:α=>1)))
source

Observables

AlgebraicAgents.getobservableFunction
getobservable(agent, args...)

Get agent's observable.

Examples

getobservable(getagent(agent, "../model"), "observable_name")
-getobservable(getagent(agent, "../model"), 1)
source

Solving & plotting

AlgebraicAgents.step!Function
step!(agent, t=projected_to(agent))

Performs a single evolutionary step of the hierarchy. To avoid frontrunning, solutions will be projected only up to time t. This is a two-phase step; the corresponding stepping functions are _prestep! and step!.

More particular behavior can be implemented using Opera protocol.

For custom agents' types, it suffices to implement _step!.

Return values

Return true if all internal agent's time horizon was reached. Else return the minimum time up to which the agent's solution was projected.

source
AlgebraicAgents.simulateFunction
simulate(agent::AbstractAlgebraicAgent, max_t=Inf)::AbstractAlgebraicAgent

Solves an (initialized) problem. Runs a loop until all the agents return true (reached simulation horizon) or nothing (delegated evolution), or until the simulation horizon reaches max_t. Avoids front-running.

Examples

sol = simulate(model)
source

Paths

Implements path-like structure of agents.

AlgebraicAgents.getagentFunction

Retrieve an agent at path, relatively to agent.

source
getagent(a::AbstractAlgebraicAgent, uuid::UUID)

Get an agent given its uuid.

Examples

getagent(a, UUID("2a634aad-0fbe-4a91-a605-bfbef4d57f95"))
-getagent(a, uuid"2a634aad-0fbe-4a91-a605-bfbef4d57f95")
source
getagent(agent::AbstractAlgebraicAgent, path::AbstractString)

Get an agent given its relative path.

Examples

getagent(a, "../agent")
source
getagent(agent::AbstractAlgebraicAgent, path::Union{Glob.FilenameMatch, Regex})

Get an agent given a regex or glob string.

Examples

getagent(a, r"agent.*")
-getagent(a, glob"**/agent/")
source
AlgebraicAgents.by_nameFunction
by_name(agent, name::AbstractString; inners_only=false)

Return agents in the hierachy with the given name. If inners_only==true, consider descendants of agent only.

source
by_name(agent, name::Union{Glob.FilenameMatch, Regex})

Return agents in the hierarchy whose names match the given wildcard. If inners_only==true, consider descendants of agent only.

source

Opera, a dynamic structure to facilitate complex interactions

AlgebraicAgents.OperaType
Opera(uuid2agent_pairs...)

A dynamic structure that

  • contains a directory of agents (dictionary of uuid => agent pairs);
  • keeps track of, and executes, futures (delayed interactions);
  • keeps track of, and executes, system controls;
  • keeps track of, and executes, instantious interactions;

Futures

You may schedule function calls, to be executed at predetermined points of time. An action is modeled as a tuple (id, call, time), where id is an optional textual identifier of the action and call is a (parameterless) anonymous function, which will be called at the given time. Once the action is executed, the return value with corresponding action id and execution time is added to futures_log field of Opera instance.

See add_future! and @future.

Example

alice = MyAgentType("alice")
+ 0.5

For plotting, you will want to load Plots as well. Nevertheless, function draw will inform you when necessary.

Common interface

Agent properties accessors

AlgebraicAgents.setparameters!Function
setparameters!(agent, parameters)

Assign agent's parameters. Parameters are accepted in the form of a dictionary containing path => params pairs.

Examples

setparameters!(agent, Dict("agent1/agent2" => Dict(:α=>1)))
source

Observables

AlgebraicAgents.getobservableFunction
getobservable(agent, args...)

Get agent's observable.

Examples

getobservable(getagent(agent, "../model"), "observable_name")
+getobservable(getagent(agent, "../model"), 1)
source

Solving & plotting

AlgebraicAgents.step!Function
step!(agent, t=projected_to(agent))

Performs a single evolutionary step of the hierarchy. To avoid frontrunning, solutions will be projected only up to time t. This is a two-phase step; the corresponding stepping functions are _prestep! and step!.

More particular behavior can be implemented using Opera protocol.

For custom agents' types, it suffices to implement _step!.

Return values

Return true if all internal agent's time horizon was reached. Else return the minimum time up to which the agent's solution was projected.

source
AlgebraicAgents.simulateFunction
simulate(agent::AbstractAlgebraicAgent, max_t=Inf)::AbstractAlgebraicAgent

Solves an (initialized) problem. Runs a loop until all the agents return true (reached simulation horizon) or nothing (delegated evolution), or until the simulation horizon reaches max_t. Avoids front-running.

Examples

sol = simulate(model)
source

Paths

Implements path-like structure of agents.

AlgebraicAgents.getagentFunction

Retrieve an agent at path, relatively to agent.

source
getagent(a::AbstractAlgebraicAgent, uuid::UUID)

Get an agent given its uuid.

Examples

getagent(a, UUID("2a634aad-0fbe-4a91-a605-bfbef4d57f95"))
+getagent(a, uuid"2a634aad-0fbe-4a91-a605-bfbef4d57f95")
source
getagent(agent::AbstractAlgebraicAgent, path::AbstractString)

Get an agent given its relative path.

Examples

getagent(a, "../agent")
source
getagent(agent::AbstractAlgebraicAgent, path::Union{Glob.FilenameMatch, Regex})

Get an agent given a regex or glob string.

Examples

getagent(a, r"agent.*")
+getagent(a, glob"**/agent/")
source
AlgebraicAgents.by_nameFunction
by_name(agent, name::AbstractString; inners_only=false)

Return agents in the hierachy with the given name. If inners_only==true, consider descendants of agent only.

source
by_name(agent, name::Union{Glob.FilenameMatch, Regex})

Return agents in the hierarchy whose names match the given wildcard. If inners_only==true, consider descendants of agent only.

source

Opera, a dynamic structure to facilitate complex interactions

AlgebraicAgents.OperaType
Opera(uuid2agent_pairs...)

A dynamic structure that

  • contains a directory of agents (dictionary of uuid => agent pairs);
  • keeps track of, and executes, futures (delayed interactions);
  • keeps track of, and executes, system controls;
  • keeps track of, and executes, instantious interactions;

Futures

You may schedule function calls, to be executed at predetermined points of time. An action is modeled as a tuple (id, call, time), where id is an optional textual identifier of the action and call is a (parameterless) anonymous function, which will be called at the given time. Once the action is executed, the return value with corresponding action id and execution time is added to futures_log field of Opera instance.

See add_future! and @future.

Example

alice = MyAgentType("alice")
 interact = agent -> wake_up!(agent)
 @future alice 5.0 interact(alice) "alice_schedule"

The solver will stop at t=5 and call the function () -> interact(alice) (a closure is taken at the time when @future is invoked). This interaction is identified as "alice_schedule".

Control Interactions

You may schedule control function calls, to be executed at every step of the model. An action is modeled as a tuple (id, call), where id is an optional textual identifier of the action, and call is a (parameterless) anonymous function. Once the action is executed, the return value with corresponding action id and execution time is added to controls_log field of Opera instance.

See add_control! and @control.

Example

system = MyAgentType("system")
 control = agent -> agent.temp > 100 && cool!(agent)
 @control system control(system) "temperature control"

At each step, the solver will call the function () -> control(system) (a closure is taken at the time when @future is invoked).

Instantious Interactions

You may schedule additional interactions which exist within a single step of the model; such actions are modeled as named tuples (id, priority=0., call). Here, call is a (parameterless) anonymous function.

They exist within a single step of the model and are executed after the calls to _prestep! and _step! finish, in the order of the assigned priorities.

In particular, you may schedule interactions of two kinds:

  • poke(agent, priority), which will translate into a call () -> _interact!(agent), with the specified priority,
  • @call opera expresion priority, which will translate into a call () -> expression, with the specified priority.

See poke and @call.

Examples

# `poke`
 poke(agent, 1.) # call `_interact!(agent)`; this call is added to the instantious priority queue with priority 1
# `@call`
 bob_agent = only(getagent(agent, r"bob"))
-@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)` with priority 0
source
AlgebraicAgents.pokeFunction
poke(agent, priority=0[, id])

Poke an agent in the current time step. Translates to a call () -> _interact(agent), see @call.

Interactions are implemented within an instance Opera, sorted by their priorities.

See also Opera.

Examples

poke(agent)
-poke(agent, 1.) # with priority equal to 1
source
AlgebraicAgents.@callMacro
@call agent call [priority[, id]]
+@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)` with priority 0
source
AlgebraicAgents.pokeFunction
poke(agent, priority=0[, id])

Poke an agent in the current time step. Translates to a call () -> _interact(agent), see @call.

Interactions are implemented within an instance Opera, sorted by their priorities.

See also Opera.

Examples

poke(agent)
+poke(agent, 1.) # with priority equal to 1
source
AlgebraicAgents.@callMacro
@call agent call [priority[, id]]
 @call opera call [priority[, id]]

Schedule an interaction (call), which will be executed in the current time step. Here, call will translate into a function () -> call.

Interactions are implemented within an instance Opera, sorted by their priorities.

See also Opera.

Examples

bob_agent = only(getagent(agent, r"bob"))
-@call agent wake_up(bob_agent) # translates into `() -> wake_up(bob_agent)`
source
AlgebraicAgents.add_instantious!Function
add_instantious!(opera, call, priority=0[, id])
-add_instantious!(agent, call, priority=0[, id])

Schedule a call to be executed in the current time step.

Interactions are implemented within an instance Opera, sorted by their priorities.

See also Opera.

Examples

add_instantious!(agent, () -> wake_up(agent))
source
AlgebraicAgents.add_instantious!Function
add_instantious!(opera, call, priority=0[, id])
+add_instantious!(agent, call, priority=0[, id])

Schedule a call to be executed in the current time step.

Interactions are implemented within an instance Opera, sorted by their priorities.

See also Opera.

Examples

add_instantious!(agent, () -> wake_up(agent))
source
AlgebraicAgents.@futureMacro
@future opera time call [id]
 @future agent time call [id]

Schedule a (delayed) execution of call at time. Optionally, provide a textual identifier id of the action.

call is an expression, which will be wrapped into a function () -> call (taking closure at the time when @future is invoked).

See also @future and Opera.

Examples

alice = MyAgentType("alice")
 interact = agent -> wake_up!(agent)
-@future alice 5.0 interact(alice) "alice_schedule" # stop at `t=5`
source
AlgebraicAgents.add_future!Function
add_future!(opera, time, call[, id])
 add_future!(agent, time, call[, id])

Schedule a (delayed) execution of call at time. Optionally, provide a textual identifier id of the action.

Here, call has to follow either of the following forms: - be parameterless, - be a function of Opera instance, - be a function of the topmost agent in the hierarchy. This follows the dynamic dispatch.

See also Opera.

Examples

alice = MyAgentType("alice")
 interact = agent -> wake_up!(agent)
-add_future!(alice, 5.0, () -> interact(alice), "alice_schedule")
source
AlgebraicAgents.@controlMacro
@control opera call [id]
 @control agent call [id]

Add a control to the system. Optionally, provide a textual identifier id of the action.

call is an expression, which will be wrapped into an anonymous, parameterless function () -> call.

See also Opera.

Examples

system = MyAgentType("system")
 control = agent -> agent.temp > 100 && cool!(agent)
-@control system control(system) "temperature control"
source
AlgebraicAgents.add_control!Function
add_control!(opera, call[, id])
 add_control!(agent, call[, id])

Add a control to the system. Optionally, provide a textual identifier id of the action.

Here, call has to follow either of the following forms: - be parameterless, - be a function of Opera instance, - be a function of the topmost agent in the hierarchy. This follows the dynamic dispatch.

See also @control and Opera.

Examples

system = MyAgentType("system")
 control = agent -> agent.temp > 100 && cool!(agent)
-add_control!(system, () -> control(system), "temperature control")
source

Operations

Defines sums of agents.

AlgebraicAgents.:⊕Function
⊕(models::Vararg{AbstractAlgebraicAgent, N}; name)

Algebraic sum of algebraic models. Optionally specify resulting model's name.

By default, outputs an instance of FreeAgent.

Examples

⊕(m1, m2; name="diagram1") ⊕ ⊕(m3, m4; name="diagram2");
source
⊕(system1, system2; diagram=pattern, name)
+add_control!(system, () -> control(system), "temperature control")
source

Operations

Defines sums of agents.

AlgebraicAgents.:⊕Function
⊕(models::Vararg{AbstractAlgebraicAgent, N}; name)

Algebraic sum of algebraic models. Optionally specify resulting model's name.

By default, outputs an instance of FreeAgent.

Examples

⊕(m1, m2; name="diagram1") ⊕ ⊕(m3, m4; name="diagram2");
source
⊕(system1, system2; diagram=pattern, name)
 ⊕([system1, system2]; diagram=pattern, name)
-⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
⊕(system1, system2; diagram=pattern, name)
+⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
⊕(system1, system2; diagram=pattern, name)
 ⊕([system1, system2]; diagram=pattern, name)
-⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
⊕(system1, system2; diagram=pattern, name)
+⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
⊕(system1, system2; diagram=pattern, name)
 ⊕([system1, system2]; diagram=pattern, name)
-⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
⊕(system1, system2; diagram=pattern, name)
+⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
⊕(system1, system2; diagram=pattern, name)
 ⊕([system1, system2]; diagram=pattern, name)
-⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
AlgebraicAgents.@sumMacro
@sum models...

Perform an algebraic sum of algebraic models (flatten arguments to ⊕).

Examples

@sum m1 m2 m3 m4 # == ⊕(m1, m2, m3, m4)
source

Entangle and disentangle agents hierarchies.

AlgebraicAgents.disentangle!Function
disentangle!(agent)

Detach an agent from its parent. Optionally set remove_relpathrefs=false keyword to skip removing the relative pathrefs.

Examples

disentangle!(agent)
source

Agent type constructors

Supports convenient agent subtyping.

AlgebraicAgents.@aagentMacro
@aagent [OptionalBasetype=FreeAgent] [OptionalSupertype=AbstractAlgebraicAgent] struct my_agent
+⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source
AlgebraicAgents.@sumMacro
@sum models...

Perform an algebraic sum of algebraic models (flatten arguments to ⊕).

Examples

@sum m1 m2 m3 m4 # == ⊕(m1, m2, m3, m4)
source

Entangle and disentangle agents hierarchies.

AlgebraicAgents.disentangle!Function
disentangle!(agent)

Detach an agent from its parent. Optionally set remove_relpathrefs=false keyword to skip removing the relative pathrefs.

Examples

disentangle!(agent)
source

Agent type constructors

Supports convenient agent subtyping.

AlgebraicAgents.@aagentMacro
@aagent [OptionalBasetype=FreeAgent] [OptionalSupertype=AbstractAlgebraicAgent] struct my_agent
     extra_fields...
 end

Define a custom agent type, and include fields expected by default interface methods (see FreeAgent).

Fields are mutable by default, but can be declared immutable using const keyword.

Provides a constructor which takes agent's name at the input, and populates the common fields.

Example

@aagent struct Molecule
     age::Float64
@@ -61,11 +61,11 @@
     field2::P
 end
 
-MyAgent{Float64, Int}("myagent", 1, 2)
source

To provide custom specialization of @aagent convenience macros, see AlgebraicAgents.define_agent.

Walks

Walk agents' hierarchy.

AlgebraicAgents.prewalk_retFunction

Applies f to each agent. Applies f to an agent before visiting its inners. The results of each application of f are appended to a vector and returned.

source
AlgebraicAgents.postwalk_retFunction

Applies f to each agent. Applies f to an agent after visiting its inners. The results of each application of f are appended to a vector and returned.

source

Utility functions

Wrap a dynamical system, extract agent wrap

AlgebraicAgents.wrap_systemFunction
wrap_system(name, system, args...; kwargs...)

Typically, the function will dispatch on the type of system and initialise an algebraic agent which wraps the core dynamical system. This allows you to specify the core dynamics directly using a third-party package syntax and hide the internals on this package's side from the user.

For instance, you may define a method wrap_system(name, prob::DiffEqBase.DEProblem), which internally will invoke the constructor of DiffEqAgent.

Examples

wrap_system("ode_agent", ODEProblem(f, u0, tspan))
-wrap_system("abm_agent", ABM(agent, space; properties))
source
AlgebraicAgents.extract_agentFunction
extract_agent

Extract an agent from as a property of the dynamical system (wrapped by the agent).

Examples

agent = extract_agent(params) # for SciML integration
-agent = extract_agent(model, agent) # for ABM integration
source

Flat representation

Default plots for custom agent types

AlgebraicAgents.@draw_dfMacro
@draw_df T field

A macro to define _draw(T) such that it will plot a DataFrame stored under field.

Requires DataFrames and Plots to be available.

Examples

@draw_df my_type log # will plot `log` property (a DataFrame) of `my_type`'s instance
source

Helper functions for Mermaid diagrams

AlgebraicAgents.typetree_mmdFunction
typetree_mmd(T, TT; rem = false)

Return a Vector{String} of the type hierarchy with type T, in format suitable for making Mermaid class diagrams. For the root case (where T is the top of the hierarchy), TT may be set to nothing (default argument).

The keyword argument rem can be set to true to strip the module prefix from typenames. This is useful for Mermaid diagrams, because the Mermaid classDiagram does not currently support "." characters in class names.

Examples

# the following may be pasted into the Mermaid live editor:
+MyAgent{Float64, Int}("myagent", 1, 2)
source

To provide custom specialization of @aagent convenience macros, see AlgebraicAgents.define_agent.

Walks

Walk agents' hierarchy.

AlgebraicAgents.prewalk_retFunction

Applies f to each agent. Applies f to an agent before visiting its inners. The results of each application of f are appended to a vector and returned.

source
AlgebraicAgents.postwalk_retFunction

Applies f to each agent. Applies f to an agent after visiting its inners. The results of each application of f are appended to a vector and returned.

source

Utility functions

Wrap a dynamical system, extract agent wrap

AlgebraicAgents.wrap_systemFunction
wrap_system(name, system, args...; kwargs...)

Typically, the function will dispatch on the type of system and initialise an algebraic agent which wraps the core dynamical system. This allows you to specify the core dynamics directly using a third-party package syntax and hide the internals on this package's side from the user.

For instance, you may define a method wrap_system(name, prob::DiffEqBase.DEProblem), which internally will invoke the constructor of DiffEqAgent.

Examples

wrap_system("ode_agent", ODEProblem(f, u0, tspan))
+wrap_system("abm_agent", ABM(agent, space; properties))
source
AlgebraicAgents.extract_agentFunction
extract_agent

Extract an agent from as a property of the dynamical system (wrapped by the agent).

Examples

agent = extract_agent(params) # for SciML integration
+agent = extract_agent(model, agent) # for ABM integration
source

Flat representation

Default plots for custom agent types

AlgebraicAgents.@draw_dfMacro
@draw_df T field

A macro to define _draw(T) such that it will plot a DataFrame stored under field.

Requires DataFrames and Plots to be available.

Examples

@draw_df my_type log # will plot `log` property (a DataFrame) of `my_type`'s instance
source

Helper functions for Mermaid diagrams

AlgebraicAgents.typetree_mmdFunction
typetree_mmd(T, TT; rem = false)

Return a Vector{String} of the type hierarchy with type T, in format suitable for making Mermaid class diagrams. For the root case (where T is the top of the hierarchy), TT may be set to nothing (default argument).

The keyword argument rem can be set to true to strip the module prefix from typenames. This is useful for Mermaid diagrams, because the Mermaid classDiagram does not currently support "." characters in class names.

Examples

# the following may be pasted into the Mermaid live editor:
 # https://mermaid.live/
-print(join(typetree_mmd(Integer), ""))
source
AlgebraicAgents.agent_hierarchy_mmdFunction
agent_hierarchy_mmd(a; use_uuid = 0)

This function can help display the agent hierarchy for concrete models. It assumes the user wants to pass the results into a Mermaid diagram for easier visualization of concrete model instantiations. The kwarg use_uuid will append the last use_uuid digits of each agent to their name following an underscore. This can be useful if it is not possible to distinguish unique agents purely by their name alone.

Examples

# the following may be pasted into the Mermaid live editor:
+print(join(typetree_mmd(Integer), ""))
source
AlgebraicAgents.agent_hierarchy_mmdFunction
agent_hierarchy_mmd(a; use_uuid = 0)

This function can help display the agent hierarchy for concrete models. It assumes the user wants to pass the results into a Mermaid diagram for easier visualization of concrete model instantiations. The kwarg use_uuid will append the last use_uuid digits of each agent to their name following an underscore. This can be useful if it is not possible to distinguish unique agents purely by their name alone.

Examples

# the following may be pasted into the Mermaid live editor:
 # https://mermaid.live/
 
 @aagent FreeAgent struct AgentType1 end
@@ -79,10 +79,10 @@
 
 # print last 4 digits of UUIDs
 hierarchy = agent_hierarchy_mmd(base, use_uuid = 4)
-print(join(hierarchy,""))
source

Queries

It is possible to run filter and transform queries on agent hierarchies.

Filter queries

AlgebraicAgents.FilterQueryType
FilterQuery(query)

Simple property query; references agents via underscores _.

A query on an agent may result in an error; in that case, the agent will fail the filter condition by default.

See also @f_str, filter.

Examples

filter(agents, f"_.age > 21 && _.name ∈ ['a', 'b']")
-agents |> @filter _.age > 21 && _.name ∈ ['a', 'b']
source
AlgebraicAgents.@f_strMacro
f"query"

Turn a query string into a query instance, see also FilterQuery.

Supports string interpolations.

Examples

filter(agents, f"_.age > 1 && _.name ∈ ['a', 'b']")
-i = 1; filter(agents, f"_.age > $i && _.name ∈ ['a', 'b']")
source
Base.filterMethod
filter(agent::AbstractAlgebraicAgent, queries...)
-filter(agents::Vector{<:AbstractAlgebraicAgent}, queries...)

Run filter query on agents in a hierarchy.

Examples

filter(agent, f"_.age > 21 && _.name ∈ ['a', 'b']") # filter query
source

To provide custom filter query types, you need to implement AlgebraicAgents._filter low-level matching method.

Transform queries

AlgebraicAgents.TransformQueryType
TransformQuery(name, query)

Simple transform query; references agents via underscores _.

See also @transform.

Examples

agent |> @transform(name=_.name)
-agent |> @transform(name=_.name, _.age)
source
AlgebraicAgents.@transformMacro
@transform queries...

Turn transform queries into an anonymous function of agents' hierarchy. See also TransformQuery.

Accepts both anonymous queries (_.name) and named queries (name=_.name). By default, includes agent's uuid.

source

Queries

It is possible to run filter and transform queries on agent hierarchies.

Filter queries

AlgebraicAgents.FilterQueryType
FilterQuery(query)

Simple property query; references agents via underscores _.

A query on an agent may result in an error; in that case, the agent will fail the filter condition by default.

See also @f_str, filter.

Examples

filter(agents, f"_.age > 21 && _.name ∈ ['a', 'b']")
+agents |> @filter _.age > 21 && _.name ∈ ['a', 'b']
source
AlgebraicAgents.@f_strMacro
f"query"

Turn a query string into a query instance, see also FilterQuery.

Supports string interpolations.

Examples

filter(agents, f"_.age > 1 && _.name ∈ ['a', 'b']")
+i = 1; filter(agents, f"_.age > $i && _.name ∈ ['a', 'b']")
source
Base.filterMethod
filter(agent::AbstractAlgebraicAgent, queries...)
+filter(agents::Vector{<:AbstractAlgebraicAgent}, queries...)

Run filter query on agents in a hierarchy.

Examples

filter(agent, f"_.age > 21 && _.name ∈ ['a', 'b']") # filter query
source

To provide custom filter query types, you need to implement AlgebraicAgents._filter low-level matching method.

Transform queries

AlgebraicAgents.TransformQueryType
TransformQuery(name, query)

Simple transform query; references agents via underscores _.

See also @transform.

Examples

agent |> @transform(name=_.name)
+agent |> @transform(name=_.name, _.age)
source
AlgebraicAgents.@transformMacro
@transform queries...

Turn transform queries into an anonymous function of agents' hierarchy. See also TransformQuery.

Accepts both anonymous queries (_.name) and named queries (name=_.name). By default, includes agent's uuid.

source
AlgebraicAgents.transformFunction
transform(agent::AbstractAlgebraicAgent, queries...)
 tranform(agent::Vector{<:AbstractAlgebraicAgent}, queries...)

Run transform query on agents in a hierarchy.

A query on an agent may result in an error; in that case, the respective agent's output is omitted for the result.

See also @transform.

Examples

agent |> @transform(name=_.name)
-agent |> @transform(name=_.name, _.age)
source
+agent |> @transform(name=_.name, _.age)
source
diff --git a/dev/integrations.html b/dev/integrations.html index f072a7e..eaf377a 100644 --- a/dev/integrations.html +++ b/dev/integrations.html @@ -1,12 +1,12 @@ -Integrations · AlgebraicAgents.jl

Integrations

SciML Integration

Agent Constructors

AlgebraicAgents.DiffEqAgentType
DiffEqAgent(name, problem[, alg]; observables=nothing, kwargs...)

Initialize DE problem algebraic wrap.

Keywords

  • observables: either nothing or a dictionary which maps keys to observable's positional index in u,
  • other kwargs will be passed to the integrator during initialization step.
source

AlgebraicDynamics.jl Integration

Agent Constructors

AlgebraicAgents.GraphicalAgentType
GraphicalAgent(name, model)

Initialize algebraic wrap of either an AbstractResourceSharer or a AbstractMachine.

The wrapped AbstractResourceSharer or AbstractMachine is stored as the property system.

Examples

GraphicalAgent("rabbit", ContinuousMachine{Float64}(1,1,1, dotr, (u, p, t) -> u))
source

Conversion to DiffEqAgent

AlgebraicAgents.DiffEqAgentMethod
DiffEqAgent(agent::GraphicalAgent, u0, tspan, p; alg, kwargs...)

Infer a problem type parametrized by agent.system, and create an appropriate DEProblem. Moreover, wrap this problem as an instance of DiffEqAgent; this contains agent's inner hierarchy.

Examples

DiffEqAgent(system, u0, tspan, params)
-DiffEqAgent(system, u0, tspan, params; alg=Tsit5())
source

Sums

AlgebraicAgents.:⊕Method
⊕(system1, system2; diagram=pattern, name)
+Integrations · AlgebraicAgents.jl

Integrations

SciML Integration

Agent Constructors

AlgebraicAgents.DiffEqAgentType
DiffEqAgent(name, problem[, alg]; observables=nothing, kwargs...)

Initialize DE problem algebraic wrap.

Keywords

  • observables: either nothing or a dictionary which maps keys to observable's positional index in u,
  • other kwargs will be passed to the integrator during initialization step.
source

AlgebraicDynamics.jl Integration

Agent Constructors

AlgebraicAgents.GraphicalAgentType
GraphicalAgent(name, model)

Initialize algebraic wrap of either an AbstractResourceSharer or a AbstractMachine.

The wrapped AbstractResourceSharer or AbstractMachine is stored as the property system.

Examples

GraphicalAgent("rabbit", ContinuousMachine{Float64}(1,1,1, dotr, (u, p, t) -> u))
source

Conversion to DiffEqAgent

AlgebraicAgents.DiffEqAgentMethod
DiffEqAgent(agent::GraphicalAgent, u0, tspan, p; alg, kwargs...)

Infer a problem type parametrized by agent.system, and create an appropriate DEProblem. Moreover, wrap this problem as an instance of DiffEqAgent; this contains agent's inner hierarchy.

Examples

DiffEqAgent(system, u0, tspan, params)
+DiffEqAgent(system, u0, tspan, params; alg=Tsit5())
source

Sums

AlgebraicAgents.:⊕Method
⊕(system1, system2; diagram=pattern, name)
 ⊕([system1, system2]; diagram=pattern, name)
-⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source

Agents.jl Integration

The integration can be loaded as:

Agent Constructors

AlgebraicAgents.ABMAgentType
ABMAgent(name, abm; kwargs...)

Initialize ABMAgent, incl. hierarchy of ABM's agents.

Configure the evolutionary step, logging, and step size by keyword arguments below.

Arguments

- `agent_step!`, `model_step!`: same meaning as in `Agents.step!`
+⊕(Dict(:system1 => system1, :system2 => system2); diagram=pattern, name)

Apply oapply(diagram, systems...) and wrap the result as a GraphicalAgent.

source

Agents.jl Integration

The integration can be loaded as:

Agent Constructors

AlgebraicAgents.ABMAgentType
ABMAgent(name, abm; kwargs...)

Initialize ABMAgent, incl. hierarchy of ABM's agents.

Configure the evolutionary step, logging, and step size by keyword arguments below.

Arguments

- `agent_step!`, `model_step!`: same meaning as in `Agents.step!`
 - in general, any kwarg accepted by `Agents.run!`, incl. `adata`, `mdata`
 - `when`, `when_model`: when to collect agents data, model data
 true by default, and performs data collection at every step
 if an `AbstractVector`, checks if `t ∈ when`; otherwise a function (model, t) -> ::Bool
 - `step_size`: how far the step advances, either a float or a function (model, t) -> size::Float64
-- `tspan`: solution horizon, defaults to `(0., Inf)`
source

Bindings

AlgebraicAgents.@aMacro
@a operation

Algebraic extension of add_agent!, kill_agent!.

Examples

@a add_agent!(model, 0.5)
-@a disentangle!(agent, model)
source
+- `tspan`: solution horizon, defaults to `(0., Inf)`
source

Bindings

AlgebraicAgents.@aMacro
@a operation

Algebraic extension of add_agent!, kill_agent!.

Examples

@a add_agent!(model, 0.5)
+@a disentangle!(agent, model)
source
diff --git a/dev/search.html b/dev/search.html index 099c561..1ab1399 100644 --- a/dev/search.html +++ b/dev/search.html @@ -1,2 +1,2 @@ -Search · AlgebraicAgents.jl

Loading search...

    +Search · AlgebraicAgents.jl

    Loading search...

      diff --git a/dev/sketches/agents/agents.html b/dev/sketches/agents/agents.html index 4771fc8..92eeaf0 100644 --- a/dev/sketches/agents/agents.html +++ b/dev/sketches/agents/agents.html @@ -168,7 +168,7 @@ to_collect = [(:status, f) for f in (infected, recovered, length)]
      3-element Vector{Tuple{Symbol, Function}}:
        (:status, Main.infected)
        (:status, Main.recovered)
      - (:status, length)

      We wrap the model as an agent:

      m = ABMAgent("sir_model", abm; agent_step!, tspan=(0., 100.), adata=to_collect)
      agent sir_model with uuid 194a804b of type ABMAgent 
      + (:status, length)

      We wrap the model as an agent:

      m = ABMAgent("sir_model", abm; agent_step!, tspan=(0., 100.), adata=to_collect)
      agent sir_model with uuid b5b24a4c of type ABMAgent 
          custom properties:
          abm: 
       StandardABM with 28540 agents of type PoorSoul
      @@ -180,27 +180,27 @@
          df_model: 
       0×0 DataFrame
          inner agents: 
      -    agent 5461 with uuid 0b2e9ce8 of type AAgent 
      +    agent 5461 with uuid 745a9d9d of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(5461, 2, 0, :S)
      -    agent 23986 with uuid 5e92e010 of type AAgent 
      +    agent 23986 with uuid 5af918be of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(23986, 7, 0, :S)
      -    agent 10467 with uuid ee578f08 of type AAgent 
      +    agent 10467 with uuid 709080f0 of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(10467, 3, 0, :S)
      -    agent 18565 with uuid d1246a61 of type AAgent 
      +    agent 18565 with uuid 2a3ed725 of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(18565, 5, 0, :S)
      -    agent 26767 with uuid 0215e826 of type AAgent 
      +    agent 26767 with uuid 3278510c of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(26767, 7, 0, :S)
      -    28535 more agent(s) not shown ...

      And we simulate the dynamics:

      simulate(m)
      agent sir_model with uuid 194a804b of type ABMAgent 
      +    28535 more agent(s) not shown ...

      And we simulate the dynamics:

      simulate(m)
      agent sir_model with uuid b5b24a4c of type ABMAgent 
          custom properties:
          abm: 
       StandardABM with 27413 agents of type PoorSoul
      @@ -232,76 +232,76 @@
        101 │   100.0            27392                21          27413
                                                         86 rows omitted
          inner agents: 
      -    agent 5461 with uuid 0b2e9ce8 of type AAgent 
      +    agent 5461 with uuid 745a9d9d of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(5461, 3, 24, :I)
      -    agent 23986 with uuid 5e92e010 of type AAgent 
      +    agent 23986 with uuid 5af918be of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(23986, 3, 23, :I)
      -    agent 10467 with uuid ee578f08 of type AAgent 
      +    agent 10467 with uuid 709080f0 of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(10467, 2, 20, :I)
      -    agent 18565 with uuid d1246a61 of type AAgent 
      +    agent 18565 with uuid 2a3ed725 of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(18565, 8, 22, :I)
      -    agent 26767 with uuid 0215e826 of type AAgent 
      +    agent 26767 with uuid 3278510c of type AAgent 
              custom properties:
              agent: 
       Main.PoorSoul(26767, 8, 22, :I)
           27408 more agent(s) not shown ...
      draw(m)
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/sketches/algebraicdynamics/algebraicdynamics.html b/dev/sketches/algebraicdynamics/algebraicdynamics.html index 3d261ae..9a2714f 100644 --- a/dev/sketches/algebraicdynamics/algebraicdynamics.html +++ b/dev/sketches/algebraicdynamics/algebraicdynamics.html @@ -11,7 +11,7 @@ rabbit_growth = wrap_system("rabbit_growth", ContinuousResourceSharer{Float64}(1, dotr)) rabbitfox_predation = wrap_system("rabbitfox_predation", ContinuousResourceSharer{Float64}(2, dotrf)) -fox_decline = wrap_system("fox_decline", ContinuousResourceSharer{Float64}(1, dotf))
      agent fox_decline with uuid 07c94947 of type GraphicalAgent 
      +fox_decline = wrap_system("fox_decline", ContinuousResourceSharer{Float64}(1, dotf))
      agent fox_decline with uuid 0feb1de4 of type GraphicalAgent 
          custom properties:
          model: 
          ports: ["1"]

      Define the composition pattern

      rf = @relation (rabbits,foxes) begin
      @@ -110,26 +110,26 @@
         
       
       
      -

      Compose

      rabbitfox_system = ⊕(rabbit_growth, rabbitfox_predation, fox_decline, diagram=rf, name="rabbitfox_system")
      agent rabbitfox_system with uuid a4f758bf of type GraphicalAgent 
      +

      Compose

      rabbitfox_system = ⊕(rabbit_growth, rabbitfox_predation, fox_decline, diagram=rf, name="rabbitfox_system")
      agent rabbitfox_system with uuid b8ca6e72 of type GraphicalAgent 
          custom properties:
          model: 
          ports: ["rabbits", "foxes"]
          inner agents: 
      -    agent fox_decline with uuid 07c94947 of type GraphicalAgent 
      +    agent fox_decline with uuid 0feb1de4 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]
      -    agent rabbitfox_predation with uuid 9d575c67 of type GraphicalAgent 
      +    agent rabbitfox_predation with uuid 2f9f3d21 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1", "2"]
      -    agent rabbit_growth with uuid bfeb3ebe of type GraphicalAgent 
      +    agent rabbit_growth with uuid 3caba734 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]

      Solve and plot

      u0 = [10.0, 100.0]
       params = LVector(α=.3, β=0.015, γ=0.015, δ=0.7)
       tspan = (0.0, 100.0)
      (0.0, 100.0)
      import DifferentialEquations
      -prob = DiffEqAgent(rabbitfox_system, u0, tspan, params)
      agent rabbitfox_system with uuid 35c1104d of type DiffEqAgent 
      +prob = DiffEqAgent(rabbitfox_system, u0, tspan, params)
      agent rabbitfox_system with uuid 682b6b85 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 0.0
      @@ -137,18 +137,18 @@
         10.0
        100.0
          inner agents: 
      -    agent fox_decline with uuid 07c94947 of type GraphicalAgent 
      +    agent fox_decline with uuid 0feb1de4 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]
      -    agent rabbitfox_predation with uuid 9d575c67 of type GraphicalAgent 
      +    agent rabbitfox_predation with uuid 2f9f3d21 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1", "2"]
      -    agent rabbit_growth with uuid bfeb3ebe of type GraphicalAgent 
      +    agent rabbit_growth with uuid 3caba734 of type GraphicalAgent 
              custom properties:
              model: 
      -       ports: ["1"]
      sol = simulate(prob)
      agent rabbitfox_system with uuid 35c1104d of type DiffEqAgent 
      +       ports: ["1"]
      sol = simulate(prob)
      agent rabbitfox_system with uuid 682b6b85 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 100.0
      @@ -156,67 +156,67 @@
        119.83184713731032
          0.5146458055479697
          inner agents: 
      -    agent fox_decline with uuid 07c94947 of type GraphicalAgent 
      +    agent fox_decline with uuid 0feb1de4 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]
      -    agent rabbitfox_predation with uuid 9d575c67 of type GraphicalAgent 
      +    agent rabbitfox_predation with uuid 2f9f3d21 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1", "2"]
      -    agent rabbit_growth with uuid bfeb3ebe of type GraphicalAgent 
      +    agent rabbit_growth with uuid 3caba734 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]
      draw(sol; label=["rabbits" "foxes"])
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Directed Composition

      using AlgebraicDynamics, AlgebraicDynamics.DWDDynam
       using Catlab.WiringDiagrams, Catlab.Programs
       using LabelledArrays
      @@ -224,7 +224,7 @@ 

      agent fox with uuid 12531070 of type GraphicalAgent +fox = wrap_system("fox", ContinuousMachine{Float64}(1,1,1, dotf, (u, p, t) -> u))

      agent fox with uuid 7f503a2b of type GraphicalAgent 
          custom properties:
          model: 
          ports: ["1"]

      Define the composition pattern

      rabbitfox_pattern = WiringDiagram([], [:rabbits, :foxes])
      @@ -236,22 +236,22 @@ 

      rabbitfox_system = ⊕(rabbit, fox; diagram=rabbitfox_pattern, name="rabbitfox_system")

      agent rabbitfox_system with uuid ce2ae580 of type GraphicalAgent 
      +])

      Compose

      rabbitfox_system = ⊕(rabbit, fox; diagram=rabbitfox_pattern, name="rabbitfox_system")
      agent rabbitfox_system with uuid f349ed4b of type GraphicalAgent 
          custom properties:
          model: 
          ports: ["rabbits", "foxes"]
          inner agents: 
      -    agent rabbit with uuid 8a296282 of type GraphicalAgent 
      +    agent rabbit with uuid 38d8ca85 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]
      -    agent fox with uuid 12531070 of type GraphicalAgent 
      +    agent fox with uuid 7f503a2b of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]

      Solve and plot

      u0 = [10.0, 100.0]
       params = LVector(α=.3, β=0.015, γ=0.015, δ=0.7)
       tspan = (0.0, 100.0)
      (0.0, 100.0)
      # convert the system to a problem
      -prob = DiffEqAgent(rabbitfox_system, u0, tspan, params)
      agent rabbitfox_system with uuid d8b0ba3a of type DiffEqAgent 
      +prob = DiffEqAgent(rabbitfox_system, u0, tspan, params)
      agent rabbitfox_system with uuid f17b4280 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 0.0
      @@ -259,15 +259,15 @@ 

      inner agents: - agent rabbit with uuid 8a296282 of type GraphicalAgent + agent rabbit with uuid 38d8ca85 of type GraphicalAgent custom properties: model: ports: ["1"] - agent fox with uuid 12531070 of type GraphicalAgent + agent fox with uuid 7f503a2b of type GraphicalAgent custom properties: model: ports: ["1"]

      # solve the problem
      -simulate(prob)
      agent rabbitfox_system with uuid d8b0ba3a of type DiffEqAgent 
      +simulate(prob)
      agent rabbitfox_system with uuid f17b4280 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 100.0
      @@ -275,83 +275,83 @@ 

      inner agents: - agent rabbit with uuid 8a296282 of type GraphicalAgent + agent rabbit with uuid 38d8ca85 of type GraphicalAgent custom properties: model: ports: ["1"] - agent fox with uuid 12531070 of type GraphicalAgent + agent fox with uuid 7f503a2b of type GraphicalAgent custom properties: model: ports: ["1"]

      # plot
       draw(prob; label=["rabbits" "foxes"])
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Open CPG

      using AlgebraicDynamics.CPortGraphDynam
       using AlgebraicDynamics.CPortGraphDynam: barbell

      Define the composition pattern

      rabbitfox_pattern = barbell(1)
       
      -rabbitfox_system = ⊕(rabbit, fox; diagram=rabbitfox_pattern, name="rabbitfox_system")
      agent rabbitfox_system with uuid df412278 of type GraphicalAgent 
      +rabbitfox_system = ⊕(rabbit, fox; diagram=rabbitfox_pattern, name="rabbitfox_system")
      agent rabbitfox_system with uuid 455fca39 of type GraphicalAgent 
          custom properties:
          model: 
          ports: String[]
          inner agents: 
      -    agent rabbit with uuid 8a296282 of type GraphicalAgent 
      +    agent rabbit with uuid 38d8ca85 of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]
      -    agent fox with uuid 12531070 of type GraphicalAgent 
      +    agent fox with uuid 7f503a2b of type GraphicalAgent 
              custom properties:
              model: 
              ports: ["1"]

      Solve and plot

      u0 = [10.0, 100.0]
       params = LVector(α=.3, β=0.015, γ=0.015, δ=0.7)
       tspan = (0.0, 100.0)
      (0.0, 100.0)
      # convert the system to a problem
      -prob = DiffEqAgent(rabbitfox_system, u0, tspan, params)
      agent rabbitfox_system with uuid efde49d0 of type DiffEqAgent 
      +prob = DiffEqAgent(rabbitfox_system, u0, tspan, params)
      agent rabbitfox_system with uuid 892945a5 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 0.0
      @@ -359,15 +359,15 @@ 

      Open CPGinner agents: - agent rabbit with uuid 8a296282 of type GraphicalAgent + agent rabbit with uuid 38d8ca85 of type GraphicalAgent custom properties: model: ports: ["1"] - agent fox with uuid 12531070 of type GraphicalAgent + agent fox with uuid 7f503a2b of type GraphicalAgent custom properties: model: ports: ["1"]

      # solve the problem
      -simulate(prob)
      agent rabbitfox_system with uuid efde49d0 of type DiffEqAgent 
      +simulate(prob)
      agent rabbitfox_system with uuid 892945a5 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 100.0
      @@ -375,62 +375,62 @@ 

      Open CPGinner agents: - agent rabbit with uuid 8a296282 of type GraphicalAgent + agent rabbit with uuid 38d8ca85 of type GraphicalAgent custom properties: model: ports: ["1"] - agent fox with uuid 12531070 of type GraphicalAgent + agent fox with uuid 7f503a2b of type GraphicalAgent custom properties: model: ports: ["1"]

      # plot
       draw(prob; label=["rabbits" "foxes"])
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/sketches/molecules/molecules.html b/dev/sketches/molecules/molecules.html index c5fe325..9d25d23 100644 --- a/dev/sketches/molecules/molecules.html +++ b/dev/sketches/molecules/molecules.html @@ -182,7 +182,7 @@ entangle!(therapeutic_area2, Discovery("dx", 6., 8.; dt=5.)) # log removed candidates entangle!(therapeutic_area1, FreeAgent("removed-molecules")) -entangle!(therapeutic_area2, FreeAgent("removed-molecules"))
      agent removed-molecules with uuid e13184f0 of type FreeAgent 
      +entangle!(therapeutic_area2, FreeAgent("removed-molecules"))
      agent removed-molecules with uuid 7623dd69 of type FreeAgent 
          parent: therapeutic_area2

      Integration with SciML

      Let's define toy market demand model and represent this as a stochastic differential equation defined in DifferentialEquations.jl

      # add SDE models for drug demand in respective areas
       using DifferentialEquations
       
      @@ -202,19 +202,19 @@
       
       # sync with market demand
       getobservable(getagent(pharma_model, "therapeutic_area1/demand"), "demand")
      0.9

      Let's inspect the composite model:

      # show the model
      -pharma_model
      agent pharma_model with uuid c3fd3198 of type FreeAgent 
      +pharma_model
      agent pharma_model with uuid 1052452a of type FreeAgent 
          inner agents: 
      -    agent therapeutic_area1 with uuid 6074c684 of type FreeAgent 
      +    agent therapeutic_area1 with uuid 65258017 of type FreeAgent 
              inner agents: demand, dx, removed-molecules
      -    agent therapeutic_area2 with uuid ec7a9bec of type FreeAgent 
      +    agent therapeutic_area2 with uuid 500d2662 of type FreeAgent 
              inner agents: demand, dx, removed-molecules
      getagent(pharma_model, glob"therapeutic_area?/")
      2-element Vector{FreeAgent}:
      - FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}
      - FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}

      Simulating the System

      Let's next evolve the composite model over a hundred time units. The last argument is optional here; see ?simulate for the details.

      # let the problem evolve
      + FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}
      + FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}

      Simulating the System

      Let's next evolve the composite model over a hundred time units. The last argument is optional here; see ?simulate for the details.

      # let the problem evolve
       simulate(pharma_model, 100)
       
       getagent(pharma_model, "therapeutic_area1/dx")
       
      -getagent(pharma_model, "therapeutic_area1/demand")
      agent demand with uuid 8b7dce7c of type DiffEqAgent 
      +getagent(pharma_model, "therapeutic_area1/demand")
      agent demand with uuid d9e6c185 of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 100.0
      @@ -223,78 +223,78 @@
          parent: therapeutic_area1

      Plotting

      We draw the statistics of a Discovery unit in Therapeutic Area 1:

      draw(getagent(pharma_model, "therapeutic_area1/dx"))
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Queries

      Let's now query the simulated system.

      To find out which molecules were discovered after time t=10 and removed from the track before time t=30, write

      pharma_model |> @filter(_.birth_time > 10 && _.time_removed < 30)
      624-element Vector{AbstractAlgebraicAgent}:
      - Main.LargeMolecule{name=2kxMr, uuid=4f0fb08f, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=Hl2Fl, uuid=7afd4ded, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=vnnSg, uuid=3026e37b, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=BUnv8, uuid=d52940ef, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=vJNWL, uuid=1c5168f5, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=iXkpJ, uuid=f0775e31, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=FKk7g, uuid=bae94838, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=9lHx3, uuid=0b632509, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=NXy2R, uuid=5c9c2feb, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=42qh0, uuid=4a7f406f, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      + Main.LargeMolecule{name=2kxMr, uuid=8a15b8b4, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=Hl2Fl, uuid=5eb60516, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=vnnSg, uuid=5286ee17, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=BUnv8, uuid=82f92a38, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=vJNWL, uuid=8fefa1f5, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=iXkpJ, uuid=6b7aeef6, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=FKk7g, uuid=5c208983, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=9lHx3, uuid=1b180119, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=NXy2R, uuid=0ea80c8c, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=42qh0, uuid=9fc4d835, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
        ⋮
      - Main.LargeMolecule{name=xuPKt, uuid=0b4eec28, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=aZ2Dt, uuid=7058e310, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=pzkPM, uuid=400a6c20, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=S2p3S, uuid=e2d267fc, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=4q1OL, uuid=dc851a73, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=depLz, uuid=403541ec, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=PkdVI, uuid=3fe22586, parent=FreeAgent{name=removed-molecules, uuid=0b3407a5, parent=FreeAgent{name=therapeutic_area1, uuid=6074c684, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.SmallMolecule{name=wy80X, uuid=b8afee85, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}
      - Main.LargeMolecule{name=9ksOI, uuid=4086f4c5, parent=FreeAgent{name=removed-molecules, uuid=e13184f0, parent=FreeAgent{name=therapeutic_area2, uuid=ec7a9bec, parent=FreeAgent{name=pharma_model, uuid=c3fd3198, parent=nothing}}}}

      Equivalently, we could make use of f(ilter)-strings, see @f_str, and write

      from = 10; to = 30
      + Main.LargeMolecule{name=xuPKt, uuid=ca5924d2, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=aZ2Dt, uuid=f993a999, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=pzkPM, uuid=39e89a9e, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=S2p3S, uuid=4b2f9b7a, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=4q1OL, uuid=7de53cdf, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=depLz, uuid=d0b96ec8, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=PkdVI, uuid=4b5c1e95, parent=FreeAgent{name=removed-molecules, uuid=2fb3c4fa, parent=FreeAgent{name=therapeutic_area1, uuid=65258017, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.SmallMolecule{name=wy80X, uuid=3c95b924, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}
      + Main.LargeMolecule{name=9ksOI, uuid=ed798369, parent=FreeAgent{name=removed-molecules, uuid=7623dd69, parent=FreeAgent{name=therapeutic_area2, uuid=500d2662, parent=FreeAgent{name=pharma_model, uuid=1052452a, parent=nothing}}}}

      Equivalently, we could make use of f(ilter)-strings, see @f_str, and write

      from = 10; to = 30
       pharma_model |> @filter(f"_.birth_time > $from && _.time_removed < $to");

      Let's investigate the average life time:

      # get molecules already removed from the system
       removed_molecules = pharma_model |> @filter(f"_.time_removed < Inf")
       # calculate `time_removed - birth_time`
      @@ -303,4 +303,4 @@ 

      Queries

      1.5197855029585798
      +avg_life_time = mean(x -> x.time, life_times)
      1.5197855029585798
      diff --git a/dev/sketches/sciml/sciml.html b/dev/sketches/sciml/sciml.html index a36f7c8..b49af21 100644 --- a/dev/sketches/sciml/sciml.html +++ b/dev/sketches/sciml/sciml.html @@ -39,15 +39,15 @@ @call agent custom_function(agent, t) min(2., 1.01*u + o1 + o2 + o3) -end
      f_ (generic function with 1 method)

      Another Atomic Model

      m4 = DiffEqAgent("model4", ODEProblem(f_,u0,tspan))
      agent model4 with uuid d73098d2 of type DiffEqAgent 
      +end
      f_ (generic function with 1 method)

      Another Atomic Model

      m4 = DiffEqAgent("model4", ODEProblem(f_,u0,tspan))
      agent model4 with uuid 78b5b2ab of type DiffEqAgent 
          custom properties:
          integrator: 
       t: 0.0
      -u: 0.5

      Hierarchical Sum of Atomic Models

      m = ⊕(m1, m2; name="diagram1") ⊕ ⊕(m3, m4; name="diagram2")
      agent diagram with uuid 7ce4a31c of type FreeAgent 
      +u: 0.5

      Hierarchical Sum of Atomic Models

      m = ⊕(m1, m2; name="diagram1") ⊕ ⊕(m3, m4; name="diagram2")
      agent diagram with uuid c1c3d0bf of type FreeAgent 
          inner agents: 
      -    agent diagram1 with uuid df00915e of type FreeAgent 
      +    agent diagram1 with uuid 91a03bf4 of type FreeAgent 
              inner agents: model1, model2
      -    agent diagram2 with uuid 25d8a307 of type FreeAgent 
      +    agent diagram2 with uuid 36538318 of type FreeAgent 
              inner agents: model3, model4
      # explore path-like structure of agents
       
       # index by unix-like path
      @@ -62,12 +62,12 @@
       # index by glob expression
       getagent(m, glob"**/model?/")
       getagent(m, glob"**/model?"s)
      4-element Vector{DiffEqAgent}:
      - DiffEqAgent{name=model4, uuid=d73098d2, parent=FreeAgent{name=diagram2, uuid=25d8a307, parent=FreeAgent{name=diagram, uuid=7ce4a31c, parent=nothing}}}
      - DiffEqAgent{name=model1, uuid=67799a08, parent=FreeAgent{name=diagram1, uuid=df00915e, parent=FreeAgent{name=diagram, uuid=7ce4a31c, parent=nothing}}}
      - DiffEqAgent{name=model2, uuid=292a669e, parent=FreeAgent{name=diagram1, uuid=df00915e, parent=FreeAgent{name=diagram, uuid=7ce4a31c, parent=nothing}}}
      - DiffEqAgent{name=model3, uuid=7c45e317, parent=FreeAgent{name=diagram2, uuid=25d8a307, parent=FreeAgent{name=diagram, uuid=7ce4a31c, parent=nothing}}}

      Solving

      sol = simulate(m)
      agent diagram with uuid 7ce4a31c of type FreeAgent 
      + DiffEqAgent{name=model4, uuid=78b5b2ab, parent=FreeAgent{name=diagram2, uuid=36538318, parent=FreeAgent{name=diagram, uuid=c1c3d0bf, parent=nothing}}}
      + DiffEqAgent{name=model1, uuid=b85fa34d, parent=FreeAgent{name=diagram1, uuid=91a03bf4, parent=FreeAgent{name=diagram, uuid=c1c3d0bf, parent=nothing}}}
      + DiffEqAgent{name=model2, uuid=0a43b089, parent=FreeAgent{name=diagram1, uuid=91a03bf4, parent=FreeAgent{name=diagram, uuid=c1c3d0bf, parent=nothing}}}
      + DiffEqAgent{name=model3, uuid=3d77538f, parent=FreeAgent{name=diagram2, uuid=36538318, parent=FreeAgent{name=diagram, uuid=c1c3d0bf, parent=nothing}}}

      Solving

      sol = simulate(m)
      agent diagram with uuid c1c3d0bf of type FreeAgent 
          inner agents: 
      -    agent diagram1 with uuid df00915e of type FreeAgent 
      +    agent diagram1 with uuid 91a03bf4 of type FreeAgent 
              inner agents: model1, model2
      -    agent diagram2 with uuid 25d8a307 of type FreeAgent 
      -       inner agents: model3, model4
      + agent diagram2 with uuid 36538318 of type FreeAgent + inner agents: model3, model4
      diff --git a/dev/sketches/stochastic_simulation/anderson.html b/dev/sketches/stochastic_simulation/anderson.html index 2646327..5b8ce2e 100644 --- a/dev/sketches/stochastic_simulation/anderson.html +++ b/dev/sketches/stochastic_simulation/anderson.html @@ -55,8 +55,8 @@ γ = 0.25
      0.25

      Now we make a ReactionSystem object, and initialize it to a population with 990 susceptible persons, 10 infectious persons, and 0 recovered persons. The two events in the system are infection and recovery, which fire according to the rates given by the anonymous functions passed to add_clock!.

      rs = make_reactionsystem("SIR", [990, 10, 0])
       add_clock!(rs, "infection", (x) -> β*x[2]*x[1], [-1,1,0])
       add_clock!(rs, "recovery", (x) -> γ*x[2], [0,-1,1])
      2-element Vector{NamedTuple{(:id, :call), <:Tuple{AbstractString, Function}}}:
      - (id = "control infection", call = Main.var"#9#10"{Main.Clock{Float64, Main.var"#11#12", Int64}}(Main.Clock{Float64, Main.var"#11#12", Int64}{name=infection, uuid=954350d9, parent=FreeAgent{name=clocks, uuid=addc646e, parent=Main.ReactionSystem{Float64, Int64}{name=SIR, uuid=85a6e76a, parent=nothing}}}))
      - (id = "control recovery", call = Main.var"#9#10"{Main.Clock{Float64, Main.var"#13#14", Int64}}(Main.Clock{Float64, Main.var"#13#14", Int64}{name=recovery, uuid=a4bbb75f, parent=FreeAgent{name=clocks, uuid=addc646e, parent=Main.ReactionSystem{Float64, Int64}{name=SIR, uuid=85a6e76a, parent=nothing}}}))

      Now we call simulate on the constructed system. Because a clock will return a next event time of Inf when its rate is 0 (meaning it will never fire again), when all clocks return Inf it means the simulation is over, because nothing else can happen. Therefore we pass as the second argument to simulate the largest representable floating point value. When all clocks return Inf, the minimum will be larger than this value and the simulation loop will end.

      simulate(rs, floatmax(Float64))
      agent SIR with uuid 85a6e76a of type Main.ReactionSystem{Float64, Int64} 
      + (id = "control infection", call = Main.var"#9#10"{Main.Clock{Float64, Main.var"#11#12", Int64}}(Main.Clock{Float64, Main.var"#11#12", Int64}{name=infection, uuid=25249f64, parent=FreeAgent{name=clocks, uuid=6fb5640b, parent=Main.ReactionSystem{Float64, Int64}{name=SIR, uuid=fee808fc, parent=nothing}}}))
      + (id = "control recovery", call = Main.var"#9#10"{Main.Clock{Float64, Main.var"#13#14", Int64}}(Main.Clock{Float64, Main.var"#13#14", Int64}{name=recovery, uuid=5be94647, parent=FreeAgent{name=clocks, uuid=6fb5640b, parent=Main.ReactionSystem{Float64, Int64}{name=SIR, uuid=fee808fc, parent=nothing}}}))

      Now we call simulate on the constructed system. Because a clock will return a next event time of Inf when its rate is 0 (meaning it will never fire again), when all clocks return Inf it means the simulation is over, because nothing else can happen. Therefore we pass as the second argument to simulate the largest representable floating point value. When all clocks return Inf, the minimum will be larger than this value and the simulation loop will end.

      simulate(rs, floatmax(Float64))
      agent SIR with uuid fee808fc of type Main.ReactionSystem{Float64, Int64} 
          custom properties:
          t: 48.026271541320334
          Δ: 0.600759333221049
      @@ -84,58 +84,58 @@
        1538 │ 48.0263     recovery     226      0    774
                                         1523 rows omitted
          inner agents: 
      -    agent clocks with uuid addc646e of type FreeAgent 
      +    agent clocks with uuid 6fb5640b of type FreeAgent 
              inner agents: recovery, infection

      After simulation is complete, we can extract the simulated trajectory.

      df_out = select(rs.df_output, Not(:clock));
       plot(df_out[!,:time], Matrix(df_out[:,[:X1,:X2,:X3]]), label = ["S" "I" "R"])
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Stochastic Petri Net

      Stochastic Petri nets (SPN) are a mathematical language to describe distributed systems which evolve according to a stochastic trajectory. There are many ways to define them, and for a comprehensive overview of their modeling power, we reccomend Haas (2002). We will implement a very simple SPN to set up a state transition system. Our SPN is nearly identical to the category of Petri net proposed by Kock (2023), with the addition of a rate parameter associated with each transition. When we assume that overall transition rates occur according to the mass action law multiplied by the rate constant associated with that transition, we will be able to produce a ReactionSystem that can be simulated using the code above.

      @aagent struct StochasticPetriNet
           P::Vector{Symbol}
           T::Vector{Symbol}
      @@ -165,7 +165,7 @@ 

      agent SIR with uuid d8170f00 of type Main.StochasticPetriNet +)

      agent SIR with uuid 6620a079 of type Main.StochasticPetriNet 
          custom properties:
          P: [:S, :I, :R]
          T: [:inf, :rec]
      @@ -212,7 +212,7 @@ 

      generate_reaction_system (generic function with 1 method)

      Now we can generate the reaction system which implements the stochastic dynamics of the SIR model from the Petri net representing the structural constraints of the SIR model. In this way, we seperate specification of structure from specification of dynamics. We use the same initial condition as before.

      x0 = [990, 10, 0]
      -sir_rs = generate_reaction_system(sir_spn, x0)
      agent SIR with uuid 108df710 of type Main.ReactionSystem{Float64, Int64} 
      +sir_rs = generate_reaction_system(sir_spn, x0)
      agent SIR with uuid 6605b024 of type Main.ReactionSystem{Float64, Int64} 
          custom properties:
          t: 0.0
          Δ: 0.0
      @@ -223,8 +223,8 @@ 

      inner agents: - agent clocks with uuid 9aa1d2ee of type FreeAgent - inner agents: rec, inf

      We now run another simulation.

      simulate(sir_rs, floatmax(Float64))
      agent SIR with uuid 108df710 of type Main.ReactionSystem{Float64, Int64} 
      +    agent clocks with uuid 8246342a of type FreeAgent 
      +       inner agents: rec, inf

      We now run another simulation.

      simulate(sir_rs, floatmax(Float64))
      agent SIR with uuid 6605b024 of type Main.ReactionSystem{Float64, Int64} 
          custom properties:
          t: 70.63373040837106
          Δ: 8.62602923711983
      @@ -252,54 +252,54 @@ 

      inner agents: - agent clocks with uuid 9aa1d2ee of type FreeAgent + agent clocks with uuid 8246342a of type FreeAgent inner agents: rec, inf

      We can make another plot. Although the parameters are the same, the stochastic trajectory should look a little different, due to the randomness in the two driving Poisson processes.

      df_out = select(sir_rs.df_output, Not(:clock));
       plot(df_out[!,:time], Matrix(df_out[:,[:X1,:X2,:X3]]), label = ["S" "I" "R"])
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +