Topologies
In Mango.jl agents usually communicate with each other based on a topology. The topology determines which agent can communicate with which agent. To implement this, every agent has access to a neighborhood, which is the set of all agents it can communicate with.
As it can be pretty clunky to create every neighborhood-list manually, Mango.jl provides several functions to make your life easier. For this it relys on Graphs.jl
and MetaGraphsNext.jl
as datastructure and for graph-construction
Creating topologies
First, there are several pre-defined topologies. It is also possible to use an arbitrary Graphs.jl graph. After the creation of the topology, the agents need to be added to the topology. This can be done with per_node(topology) do node ... end
. In the do-block it is possible to add agents to nodes, the do-block will be executed per vertex of your graph.
using Mango, Graphs
@agent struct MyAgent end
topology = star_topology(3) # star
topology = cycle_topology(3) # cycle
topology = complete_topology(3) # fully connected
topology = graph_topology(complete_digraph(3)) # based on arbitrary Graphs.jl AbstractGraph
per_node(topology) do node
add!(node, MyAgent())
end
# resulting topology graph
topology.graph
Meta graph based on a Graphs.SimpleGraphs.SimpleDiGraph{Int64} with vertex labels of type Int64, vertex metadata of type Mango.Node, edge metadata of type Mango.State, graph metadata given by nothing, and default weight 1.0
However, often this approach is not feasible, because you create a specific agent system with agents which need to be linked in a very specific way, such that it is not possible to assign the same agent type to every node. For this reason you can define the topology manually:
using Mango
@agent struct TopologyAgent end
container = Container()
topology = create_topology() do topology
agent0 = register(container, TopologyAgent())
agent1 = register(container, TopologyAgent())
agent2 = register(container, TopologyAgent())
n1 = add_node!(topology, agent0)
n2 = add_node!(topology, agent1)
n3 = add_node!(topology, agent2)
add_edge!(topology, n1, n2)
add_edge!(topology, n1, n3)
end
# neighbors of `agent`
topology_neighbors(container[1])
2-element Vector{AgentAddress}:
AgentAddress("agent1", nothing, nothing)
AgentAddress("agent2", nothing, nothing)
Using the topology
At this point we know how to create topologies and how to populate them. To actually use them, the function topology_neighbors
exists. The function returns a vector of AgentAddress objects, which represent all other agents in the neighborhood of agent
.