Transition Function

After the initialization, the state of the simulation is modified by so called transition functions. See Defining Transition Functions for details.

Vahana.apply!Function
apply!(sim, func, call, read, write; [add_existing, with_edge])

Apply the transition function func to the simulation state.

call must be a single agent type or a collection of agent types, likewise read and write must be a single agent/edge type or a collection of agent/edge types.

call determines for which agent types the transition function func is called. Within the transition function, an agent has access to the state of agents (including its own state) and to edges only if their types are in the read collection. Accordingly, the agent can change its own state and/or create new agents or edges only if their types are in the write collection.

Assume that T is an agent type that is in call. In case T is also in read, the transition function must have the following signature: transition_function(agent::T, id, sim), where the type declaration of agent is optional if call contains only a single type. If T is not in read, it must have the signature transition_function(::Val{T}, id::AgentID, sim::Simulation).

If T is in write, the transition function must return either an agent of type T or nothing. If nothing is returned, the agent will be removed from the simulation, otherwise the agent with id id will get the returned state after the transition function was called for all agents.

When an edge state type is in write, the current edges of that type are removed from the simulation. If you want to keep the existing edges for a specific type, you can add this type to the optional add_existing collection.

Similarly, agent types that are in the write but not in the call argument can be part of the add_existing collection, so that the existing agents of this type are retained and can only be added. For agent types in call, however, this is achieved by returning their state in the transition function.

With the keyword with_edge it is possible to restrict the set of agents for which the transition function is called to those agents who are on the target side of edges of the type with_edge. So

apply!(sim, AT, ET, []) do _, id, sim 
    if has_edge(sim, id, ET)
       do_something
    end
end

is equivalent to

apply!(sim, AT, ET, []; with_edge = ET) do _, id, sim 
    do_something
end

but saves all the has_edge checks.

This with_edge keyword should only be set when a small subset of agents possess edges of this particular type, as performance will be adversely impacted in other scenarios. Also the keyword can only be used for edgetypes without the :SingleType hint.

See also apply and the Applying Transition Function section in the tutorial

source
Vahana.applyFunction
apply!(sim, func, call, read, write; add_existing)

Call apply! with a copy of the simulation so that the state of sim itself is not changed.

Can be very useful during development, especially if Vahana is used in the REPL. However, for performance reasons, this function should not be used in the final code.

Returns the copy of the simulation.

See also apply!

source
Tip

The agent types must be immutable, but in many cases the agent returned by a transition function will have a different state than the agent specified as a parameter. If only one field is changed, we still need to copy all other fields. The Setfield.jl package can be very useful in this case.

Inside a transition function the following functions can be used to access the state of the simulation:

Globals and Parameters

Vahana.paramFunction
param(sim::Simulation, name)

Returns the value of the field name of the params struct from the Simulation constructor.

See also create_model

source

Get Agent(state)

Vahana.agentstateFunction
agentstate(sim, id::AgentID, ::Type{T})

Returns the state of an agent of type T.

In the case where the type T is not determinable when writing the code (e.g. since there may be edges between agents of different types, the function edges may also return agentIDs of different agent types), agentstate_flexible must be used instead.

Warning

if agentstate is called with a Type{T} that does not match the type of the agent with id and the vahana assertions are disabled via enable_asserts, then it is possible that the state of an incorrect agent will be returned. When the assertions are active, there is a runtime check that the agent with the ID id has indeed the type T.

source
Vahana.agentstate_flexibleFunction
agentstate_flexible(sim, id::AgentID)

Returns the state of an agent with the id, where the type of the agent is determined at runtime. If the type is known at compile time, using agentstate is preferable as this improves performance.

source

To retrieve the states of all agents connected to a target agent through edges of a specific type, the neighborstates_iter functions can be beneficial. These functions combine the capabilities of neighborids and agentstate, allowing you to easy access the desired information.

Vahana.neighborstatesFunction
neighborstates(sim::Simulation, id::AgentID, ::Type{E}, ::Type{A})

Returns the state of the agent with type A on the source of the edge of type E with agent id as target if E has the hint :SingleEdge, or a vector of these agent states otherwise.

If there is no edge with agent id as target, neighborstates returns nothing.

When the agents on the source side of the edges can have different types, and it is impossible to determine the Type{A} you can use neighborstates_flexible instead.

neighborstates is not defined if T has the hint :IgnoreFrom

Tip

If the edge type E does not have the :SingleEdge hint, neighborstates allocates memory for the vector of agent states. To avoid this allocation, you can use neighborstates_iter instead.

See also apply!, edges, neighborids, num_edges, has_edge and edgestates

source
Vahana.neighborstates_flexibleFunction
neighborstates_flexible(sim::Simulation, id::AgentID, ::Type{E})

Returns the state of the agent on the source of the edge of type E with agent id as target if E has the hint :SingleEdge, or a vector of these agent states otherwise.

If there is no edge with agent id as target, neighborstates_flexible returns nothing.

neighborstates_flexible is the type instable version of neighborstates and should be only used in the case that the type of agent can not be determined.

neighborstates_flexible is not defined if T has the hint :IgnoreFrom.

Tip

If the edge type E does not have the :SingleEdge hint, neighborstates_flexible allocates memory for the vector of agent states. To avoid this allocation, you can use neighborstates_flexible_iter instead.

See also apply!, edges, neighborids, num_edges, has_edge and edgestates

source
Vahana.neighborstates_iterFunction
neighborstates_iter(sim::Simulation, id::AgentID, ::Type{E}, ::Type{A})

Returns an iterator for the states of the agents with type A on the source of the edges of type E with agent id as target.

If there is no edge with agent id as target, the function returns nothing.

When the agents on the source side of the edges can have different types, and it is impossible to determine the Type{A} you can use neighborstates_flexible_iter instead.

neighborstates_iter is not defined if T has the hint :IgnoreFrom or :SingleEdge.

See also neighborstates, apply!, edges, neighborids, num_edges, has_edge and edgestates

source
Vahana.neighborstates_flexible_iterFunction
neighborstates_flexible_iter(sim::Simulation, id::AgentID, ::Type{E})

Returns an iterator for the states of the agents on the source of the edges of type E with agent id as target.

If there is no edge with agent id as target, the function returns nothing.

neighborstates_flexible_iter is the type instable version of neighborstates_iter and should be only used in the case that the type of agent can not be determined.

neighborstates_flexible_iter is not defined if T has the hint :IgnoreFrom or the hint :SingleEdge.

See also neighborstates_flexible, apply!, edges, neighborids, num_edges, has_edge and edgestates

source

Get Edge(state)

Vahana.edgesFunction
edges(sim, id::AgentID, ::Type{E})

Returns the edge of type E with agent id as target if E has the hint :SingleEdge, or a vector of these edges otherwise.

If there is no edge with agent id as target, edges returns nothing.

edges is not defined if E has the hint :IgnoreFrom or :Stateless.

See also apply!, neighborids, edgestates, num_edges, has_edge and neighborstates

source
Vahana.edgestatesFunction
edgestates(sim, id::AgentID, ::Type{E})

Returns the state of the edge of type E with agent id as target if E has the hint :SingleEdge, or a vector of these states otherwise.

If there is no edge with agent id as target, edgestates returns nothing.

edgestates is not defined if E has the hint :Stateless.

Tip

If the edge type E does not have the :Stateless or :SingleEdge hint, edgestates allocates memory for the vector of states. To avoid this allocation, you can use edgestates_iter instead.

See also apply!, edges, neighborids, num_edges, has_edge and neighborstates

source
Vahana.neighboridsFunction
neighborids(sim, id::AgentID, ::Type{E})

Returns the ID of the agent on the source of the edge of type E with agent id as target if E has the hint :SingleEdge, or otherwise a vector of the IDs of the agents on the source side of those edges.

If there is no edge with agent id as target, neighborids returns nothing.

neighborids is not defined if E has the hint :IgnoreFrom.

Tip

If the edge type E does not have the :Stateless or :SingleEdge hint, neighborids allocates memory for the vector of agent ids. To avoid this allocation, you can use neighborids_iter instead.

See also apply!, edges, edgestates, num_edges, has_edge and neighborstates

source

For all the function like edges that returns nothing in the case that there is no edge with the agent as target, it can be useful to increase the readability of the code by using the checked function to test for nothing.

Vahana.checkedFunction
checked(f, g, itr; kwargs...)

Calls g(f, itr; kwargs...), but only if itr != nothing.

As all the Vahana functions that access the edges of a specific agent can return nothing in the case, that there exist no incoming edge for this agent, it's often necessery to check this case.

Example:

Instead of writing

nids = neighborids(sim, id, Contact)
if nids != nothing
    foreach(nids) do nid
      add_edge!(sim, id, nid, Inform()
    end
end

you can use the checked function to write

checked(foreach, neighborids(sim, id, Contact)) do nid
    add_edge!(sim, id, nid, Inform())
end
source

Add Agents/Edges

The following functions from the [Initialization] section (initialization.md) that add new agents or edges to a simulation can also be used inside a transition function, namely:

Remove Edges

Since v1.2 it's also possible to remove edges:

Vahana.remove_edges!Function
remove_edges!(sim::Simulation, to::AgentID, ::Type{E})

Remove all edges of type E where to is at the target position.

Can only be called within a transition function, where E is in the write argument and also in the add_existing list of apply!.

source
remove_edges!(sim::Simulation, from::AgentID, to::AgentID, ::Type{E})

Removes all edges of type E with from at the source position and to at the target position of an edge. remove_edges! in this form (with from as argument) can only be called if the edge type E does not have the :IgnoreFrom hint.

Can also only be called within a transition function, where E is in the write argument and also in the add_existing list of apply!.

source