API
Express
This part contains basic convenience functions for creating and running Mango.jl simulations.
Mango.PrintingAgent
— TypeSimple agent just printing every message to @info.
Mango.activate
— Methodactivate(runnable, container_list)
Actvate the container(s), which includes starting the containers and shutting them down after the runnable has been executed.
In most cases the runnable will execute code, which starts some process (e.g. some distributed negotiation) in the system to define the objective of the agent system.
Generally this function is a convenience function and is equivalent to starting all containers in the list, executing the code represented by runnable
and shuting down the container again. Further, this function will handle errors occuring while running the runnable
and ensure the containers are shutting down.
Examples
activate(your_containers) do
# Send the first message to start the system
send_message(defined_agent, "Starting somethin", address(other_defined_agent))
# wait some time
wait(some_stopping_condition)
end
Mango.add_agent_composed_of
— Methodadd_agent_composed_of(container, roles::Role...; suggested_aid::Union{Nothing,String}=nothing, base_agent::Union{Nothing,Agent}=nothing)
Create an agent which is composed of the given roles roles...
and register the agent to the container
.
If no base_agent
is provided the agent struct used is an empty struct, which is only used as a container for the roles. The agent will be returned by the function.
Examples
agent = add_agent_composed_of(your_container, RoleA(), RoleB(), RoleC())
Mango.agent_composed_of
— Methodagent_composed_of(roles::Role...; base_agent::Union{Nothing,Agent}=nothing)
Create an agent which is composed of the given roles roles...
.
If no base_agent
is provided the agent struct used is an empty struct, which is only used as a container for the roles. The agent will be returned by the function.
Examples
agent = agent_composed_of(RoleA(), RoleB(), RoleC())
Mango.create_mqtt_container
— Functioncreate_mqtt_container(host, port, client_id; codec=nothing)
Create a container using an MQTT protocol.
The host
is expected to be the IP-adress of the broker, port
is the port of the broker, the client_id
is the id of the client which will be created and connected to the broker. Optionally you can also provide a codec as tuple of functions (first encode, second decode, see encode
and decode
).
Examples
agent = create_mqtt_container("127.0.0.1", 5555, "MyClient")
Mango.create_tcp_container
— Functioncreate_tcp_container(host, port; codec=nothing)
Create a container using an TCP protocol.
The host
is expected to be the IP-adress to bind on, port
is the port to bind on. Optionally you can also provide a codec as tuple of functions (first encode, second decode, see encode
and decode
).
Examples
agent = create_mqtt_container("127.0.0.1", 5555, "MyClient")
Mango.run_in_real_time
— Methodrun_in_real_time(runnable::Function,
n_container::Int,
container_list_creator::Function,
agents::Agent...)
Let the agents run in containers (real time).
Distributes the given agents
contained in the agenttuple to `ncontainer(real time container) and execute the
runnable` (takes the container list as argument) while the container are active to run.
Mango.run_in_real_time
— Methodrun_in_real_time(runnable::Function,
n_container::Int,
container_list_creator::Function,
agent_tuple::Tuple...)
Let the agents run in containers (real time).
Distributes the given agents contained in the agent_tuple
to n_container
(real time container) and execute the runnable
(takes the container list as argument) while the container are active to run. It is possible to add supplementary information per agent as Tuple. For example (Agent, :aid => "my_aid")
. The type of the containers are determined by the container_list_creator
(ncontainer as argument, has to return a list of container with ncontainer entries).
Mango.run_in_simulation
— Methodrun_in_simulation(runnable::Function, agents::Agent, n_steps::Int; start_time::DateTime=DateTime(2000, 1, 1), step_size_s::Int=DISCRETE_EVENT)
Let the agents run as simulation in a simulation container.
Execute the runnable
in SimulationContainer
while the container is active to run. After the runnable the simulation container is stepped n_steps
time with a step_size_s
(default is discrete event). The start time can be specified using start_time
.
Mango.run_with_mqtt
— Methodrun_with_mqtt(runnable::Function,
n_container::Int,
agents::Agent...;
broker_host::String="127.0.0.1",
broker_port::Int=1883,
codec::Union{Nothing,Tuple{Function,Function}}=(encode, decode))
Let the agents run in mqtt containers (real time).
Distributes the given agents
to n_container
(real time container) and execute the runnable
(takes the container list as argument) while the container are active to run. Here, MQTT container are created with the broker on broker_host
and at the port broker_port
. The containers are assignede client ids (client1 client2 ...)
Mango.run_with_mqtt
— Methodrun_with_mqtt(runnable::Function,
n_container::Int,
agent_tuples::Tuple...;
broker_host::String="127.0.0.1",
broker_port::Int=1883,
codec::Union{Nothing,Tuple{Function,Function}}=(encode, decode))
Let the agents run in mqtt containers (real time).
Distributes the given agents
to n_container
(real time container) and execute the runnable
(takes the container list as argument) while the container are active to run. It is possible to add supplementary information per agent as Tuple. For example (Agent, :aid => "my_aid", :topics => ["topic"])
. Here, MQTT container are created with the broker on broker_host
and at the port broker_port
. The containers are assignede client ids (client1 client2 ...)
Mango.run_with_tcp
— Methodrun_with_tcp(runnable::Function,
n_container::Int,
agents::Agent...;
host::String="127.0.0.1",
start_port::Int=5555,
codec::Union{Nothing,Tuple{Function,Function}}=(encode, decode))
Let the agents
run in tcp containers (real time).
Distributes the given agents
to n_container
(real time container) and execute the runnable
(takes the container list as argument) while the container are active to run. Here, TCP container are created on host
starting with the port start_port
.
Mango.run_with_tcp
— Methodrun_with_tcp(runnable::Function,
n_container::Int,
agent_tuples::Union{Tuple,Agent}...;
host::String="127.0.0.1",
start_port::Int=5555,
codec::Union{Nothing,Tuple{Function,Function}}=(encode, decode))
Let the agents run in tcp containers (real time).
Distributes the given agent_tuples
to n_container
(real time container) and execute the runnable
(takes the container list as argument) while the container are active to run. It is possible to add supplementary information per agent as Tuple. For example (Agent, :aid => "my_aid")
. Here, TCP container are created on host
starting with the port start_port
.
Agent and Roles
Here, the API for the agent structs created with @agent/@role is listed.
Mango.address
— Methodaddress(agent)
Return the agent address of the agent as AgentAddress
or MQTTAddress
depending on the protocol.
Mango.aid
— Methodaid(agent)
Return the aid of the agent.
Mango.forward_to
— Methodforward_to(agent, content, forward_to_address, received_meta; kwargs...)
Forward the message to a specific agent using the metadata received on handling the message. This method essentially simply calls send_message on the input given, but also adds and fills the correct metadata fields to mark the message as forwarded.
For this the following meta data is set.
- 'forwarded=true',
- 'forwardedfromaddress=address of the original sender',
- 'forwardedfromid=id of the original sender'
Mango.reply_to
— Methodreply_to(
agent::AgentInterface,
content::Any,
received_meta::AbstractDict,
)
Convenience method to reply to a received message using the meta the agent received. This reduces the regular send_message
as response send_message(agent, "Pong", AgentAddress(aid=meta["sender_id"], address=meta["sender_addr"]))
to reply_to(agent, "Pong", meta)
Furthermore it guarantees that agent address (including the tracking id, which is part of the address!) is correctly passed to the mango container.
Mango.send_and_handle_answer
— Methodsend_and_handle_answer(
response_handler::Function,
agent::AgentInterface,
content::Any,
agent_address::Address;
calling_object::Any=nothing,
kwargs...)
Convenience method for sending tracked messages with response handler to the answer.
Sends a tracked message with a required response_handler to enable to use the syntax
send_and_handle_answer(...) do agent, message, meta
# handle the answer
end
Mango.send_message
— Methodsend_message(
agent::AgentInterface,
content::Any,
agent_address::Address;
kwargs...,
)
Send a message with the content content
to the agent represented by agent_address
.
This method will always set a sender_id. Additionally, further keyword arguments can be defined to fill the internal meta data of the message.
Mango.send_tracked_message
— Methodsend_tracked_message(
agent::AgentInterface,
content::Any,
agent_address::Address;
response_handler::Function=(agent, message, meta) -> nothing,
calling_object::Any=nothing,
kwargs...,
)
Send a message with the content content
to the agent represented by agent_address
. This function will set a generated tracking_id to the address, which allows the identification of the dialog.
It is possible to define a response_handler
, to which a function can be assigned, which handles the answer to this message call. Note that the resonding agent needs to use the same tracking id in the response, ideally reply_to
is used to achieve this automatically.
This method will always set a sender_id. Additionally, further keyword arguments can be defines to fill the internal meta data of the message.
Mango.Address
— TypeSupertype of all address types
Mango.Agent
— TypeBase-type for all agents in mango. Generally exists for type-safety and default implementations across all agents.
Mango.@agent
— MacroMacro for defining an agent struct. Expects a struct definition as argument.
The macro does 3 things:
- It adds all baseline fields, defined in
AGENT_BASELINE_FIELDS
(the agent contextcontext
, the role handlerrole_handler
, and theaid
) - It adds the supertype
Agent
to the given struct. - It applies
@with_def
for default construction, the baseline fields are assigned to default values
Example
For example the usage could like this.
@agent struct MyAgent
my_own_field::String
end
# results in
@with_def mutable struct MyAgent <: Agent
# baseline fields...
my_own_field::String
my_own_field_with_default::String = "Default"
end
# so you would construct your agent like this
my_agent = MyAgent("own value", my_own_field_with_default="OtherValue")
Base.schedule
— Methodschedule(f::Function, agent::Agent, data::TaskData)
Delegates to the scheduler Scheduler
Mango.add
— Methodadd(agent::Agent, role::Role)
Add a role to the agent. This will add the role to the internal RoleHandler of the agent and it will bind the RoleContext to the role, which enables the role to interact with its environment.
Mango.add_forwarding_rule
— Methodadd_forwarding_rule(agent, from_addr::AgentAddress, to_address::AgentAddress, forward_replies::Bool)
Add a rule for message forwarding.
After calling the agent will auto-forward every message coming from from_addr
to to_address
. If forwardreplies is set, all replies from `toaddressare forwarded back to
from_addr`.
Mango.add_service!
— Methodadd_service!(agent, service)
Add a service to the agent. Every service can exists exactly one time (stored by type).
Mango.delete_forwarding_rule
— Methoddelete_forwarding_rule(agent, from_addr::AgentAddress, to_address::Union{Nothing,AgentAddress})
Delete an added forwarding rule. If to_address
is not set, all rules are removed matching from_addr
. If it set, both addresses need to match.
Mango.handle_message
— Methodhandle_message(agent::Agent, message::Any, meta::Any)
Defines a function for an agent, which will be called when a message is dispatched to the agent. This methods will be called with any arriving message (according to the multiple dispatch of julia).
Mango.on_ready
— Methodon_ready(agent::Agent)
Lifecycle Hook-in function called when the agent system as a whole is ready, the hook-in has to be manually activated using notify_ready(container::Container). If you use the activate
function, it is called automatically.
Mango.on_start
— Methodon_start(agent::Agent)
Lifecycle Hook-in function called when the container of the agent has been started, depending on the container type it may not be called (if there is no start at all, f.e. the simulation container)
Mango.roles
— Methodroles(agent)
Return all roles of the given agent
Mango.service_of_type
— Methodservice_of_type(agent, type::Type{T}, default=nothing)::Union{T,Nothing} where {T}
Return the current agent service of the type type
.
If a default is set, this default service will be added to the agent as service of te type `type. The function is especially useful if you want to extend the functionality of the agent without having to change the internals of the agent, as this functions enables the user to add arbitrary data to the agent on which functions can be defined.
Mango.services
— Methodservices(agent)::Dict{DataType,Any}
Return a list of services, which were added to the agent.
Mango.shutdown
— Methodshutdown(agent)
Will be called on shutdown of the container, in which the agent is living
Mango.stop_all_tasks
— Methodstop_all_tasks(agent::Agent)
Delegates to the scheduler Scheduler
Mango.stop_and_wait_for_all_tasks
— Methodstop_and_wait_for_all_tasks(agent::Agent)
Delegates to the scheduler Scheduler
Mango.stop_task
— Methodstop_task(agent::Agent, t::Task)
Delegates to the scheduler Scheduler
Mango.wait_for_all_tasks
— Methodwait_for_all_tasks(agent::Agent)
Delegates to the scheduler Scheduler
Mango.AgentContext
— TypeContext of the agent. Represents the environment for the specific agent. Therefore it includes a connection to the container, including all functions used for interacting with the environment for the agent.
Mango.AgentRoleHandler
— TypeInternal data regarding the roles.
Mango.@role
— MacroMacro for defining a role struct. Expects a struct definition as argument.
The macro does 3 things:
- It adds all baseline fields, defined in
ROLE_BASELINE_FIELDS
(the role context) - It adds the supertype
Role
to the given struct. - It applies
@with_def
for default construction, the baseline fields are assigned to default values
For example the usage could like this.
@role struct MyRole
my_own_field::String
end
# results in
@with_def mutable struct MyRole <: Role
# baseline fields...
my_own_field::String
my_own_field_with_default::String = "Default"
end
# so youl would construct your role like this
my_roel = MyRole("own value", my_own_field_with_default="OtherValue")
Mango.@shared
— MacroMark the field as shared across roles.
This only works on structs with empty default constructor. Internally the marked field will be initialized with a model created by get_model
. The model will be set when the Role is added to an agent.
Example
@kwdef struct Model
field::Int = 0
end
@role struct MyRole
@shared
my_model::Model # per agent the exact same in every agent.
end
Mango.bind_context
— MethodInternal function, used to initialize to role for a specified agent
Mango.emit_event
— Methodemit_event(role::Role, event::Any; event_type::Any=nothing)
Emit an event to their subscriber.
Mango.get_model
— Methodget_model(role::Role, type::DataType)
Get a shared model from the pool. If the model does not exist yet, it will be created. Only types with default constructor are allowed!
Example
@kwdef struct ExampleModel
my_field::Int = 0
end
role = ExampleRole()
model::ExampleModel = get_model(role, ExampleModel)
model.my_field = 1
model2::ExampleModel = get_model(role, ExampleModel)
# model == model2, it will also be the same for every role!
Mango.handle_event
— Methodhandle_event(role::Role, src::Role, event::Any; event_type::Any)
Default function for arriving events, which get dispatched to the role.
Mango.handle_message
— MethodDefault function for arriving messages, which get dispatched to the role. This function will be called for every message arriving at the agent of the role.
Mango.setup
— Methodsetup(role::Role)
Hook-in function to setup the role, after it has been added to its agent.
Mango.subscribe_event
— Functionsubscribe_event(role::Role, event_type::Any, event_handler::Any, condition::Function)
Subscribe to specific types of events.
The types of events are determined by the condition
function (accepting src
and event
) and by the event_type
.
Example
struct MyEvent end
function custom_handler(role::Role, src::Role, event::Any, event_type::Any)
# do your thing
end
subscribe_event(my_role, MyEvent, custom_handler, (src, event) -> aid(src) == "agent0")
Mango.subscribe_message
— Methodsubscribe_message(role::Role, handler::Function, condition::Function)
Subscribe a message handler function (it need to have the signature (role, message, meta)) to the message dispatching. This handler function will be called everytime the given condition function ((message, meta) -> boolean) evaluates to true when a message arrives at the roles agent.
Mango.subscribe_send
— Methodsubscribe_send(role::Role, handler::Function)
Subscribe a send_message
hook in function (signature, (role, content, receiverid, receiveraddr; kwargs...)) to the message sending. The hook in function will be called every time a message is sent by the agent.
Mango.Role
— TypeDefines the type Role, which is the common base types for all roles in mango.
A Role is a bundled behavivor of an agent, which shall fulfill exactly one responsibility of an agent - the role. Technically speaking roles are the way to implement the composition pattern for agents, and to introduce modular archetypes, which shall be reused in different contexts.
Mango.RoleContext
— TypeThe RoleContext
connects the role with its environment, which is mostly its agents. This is abstracted using the AgentInterface
.
Real time container
This part contains the API related to the container construction, access and management.
Mango.SENDER_ADDR
— ConstantKey for the sender address in the meta dict
Mango.SENDER_ID
— ConstantKey for the sender in the meta dict
Mango.TRACKING_ID
— ConstantKey for the tracking number used for dialogs in the meta dict
Mango.AgentAddress
— TypeDefault AgentAddress base type, where the agent identifier is based on the container created agent id (aid). Used with the TCP protocol.
Mango.ContainerInterface
— TypeSupertype of every container implementation. This acts as an interface to be used by the agents in their contexts.
Mango.MQTTAddress
— TypeConnection information for an MQTT topic on a given broker. Used with the MQTT protocol.
Mango.agents
— Methodagents(container)
Return the agents of the container. The agents have a fixed order.
Mango.notify_ready
— Methodnotify_ready(container::Container)
Mark the agent system as ready.
Mango.protocol_addr
— Methodprotocol_addr(container)
Return technical address of the container.
Mango.register
— Functionregister(
container,
agent,
suggested_aid::Union{String,Nothing}=nothing;
kwargs...,
)
Register the agent to the container. Retun the agent itself for convenience.
Normally the aid is generated, however it is possible to suggest an aid, which will be used if it has not been used yet and if it is not conflicting with the default naming pattern (agent0, agent1, ...)
Mango.send_message
— Functionsend_message(
container::ContainerInterface,
content::Any,
address::Address,
sender_id::Union{Nothing,String}=nothing;
kwargs...,
)
Send a message message
using the given container container
to the given address. Additionally, further keyword arguments can be defines to fill the internal meta data of the message.
Mango.shutdown
— Methodshutdown(container)
Shutdown the container. Here all loops are closed, resources freed. It is recommended to use activate
instead of shutting down manually.
Mango.start
— Methodstart(container)
Start the container. It is recommended to use activate
instead of starting manually.
What exactly happend highly depends on the protocol and the container implmentation. For example, for TCP the container binds on IP and port, and the listening loop started.
Mango.Container
— TypeThe default container struct, representing the container as actor. The container is implemented by composition. This means the container consists of different implementations of base types, which define the behavior of the container itself. That being said, the same container generally able to send messages via different protocols using different codecs.
Mango.send_message
— Methodsend_message(
container::Container,
content::Any,
mqtt_address::MQTTAddress,
kwargs...,
)
Send message version for MQTT topics. Note that there is no local message forwarding here because messages always get pushed to a broker and are not directly addressed to an agennt.
Mango.MQTTProtocol
— TypeProtocol that abstracts a Mosquitto.jl client for Mango agents.
Creation
MQTTProtocol(client_id::String, broker_addr::InetAddr)
Create an MQTT client that connects to the broker at broker_addr
with a client_id
.
Fields
- client - Mosquitto.jl client
- broker_addr - address of the MQTT broker to connect to
- connected - internal flag indicating connection status
- active - internal flag indicating listen loop activity
- msg_channel - message channel of the MQTT client
- conn_channel - connection channel of the MQTT client
- topictoaid - internal dictionary to track which registered agent is subscribed to which topic
Base.close
— Methodclose(protocol::MQTTProtocol)
Disconnect the client from the broker and stop the message loop.
Mango.id
— Methodid(protocol::MQTTProtocol)
Return the name the client is registered with at its broker.
Mango.init
— Methodinit(protocol::MQTTProtocol, stop_check::Function, data_handler::Function)
Initialize the Mosquitto looping task for the provided protocol
and forward incoming messages to data_handler
.
Mango.notify_register
— Methodnotify_register(protocol::MQTTProtocol, aid::String; kwargs...)
Notify the protocol
MQTT client that a new agent with aid
has been registered.
Registration expects a kwarg topics
to subscribe the agent to. If any topic is not yet subscribed by the client subscribe
is called for it.
Mango.parse_id
— Methodparse_id(_::MQTTProtocol, id::Any)::String
Return the id
of the protocol as string (for compliance with container core).
Mango.send
— Methodsend(protocol::MQTTProtocol, destination::String, message::Any)
Send a message
to topic destination
on the clients MQTT broker.
Returns
Return value and message id from MQTT library.
Mango.subscribe
— Methodsubscribe(protocol::MQTTProtocol, topic::String; qos::Int=1)
Subscribe the MQTT client of the protocol
to topic
with the given qos
setting.
Returns
The Mosquitto error code and the message id.
Mango.Protocol
— TypeType for all implementations of protocols, acts like an interface. A protocol defines the way message are processed and especially sent and received to an other peer. F.E. A protocol could be to send messages using a plain TCP connection, which would indicate that an internet address (host + port) is required for the communication.
The parameterized type T indicates type, which defines the address data of the receiver and sender.
Every protocol has to define two methods.
- send: defines the behavior of the protocol when an agents sends a messages
- init: defines the necessary steps to initialize (especially) the receiver loop and
therefore accepts a stop check and a data handler function to indicate when the receiver should stop,
respectively how to dispatch the received message to the correct agent
Mango.id
— Methodid(protocol::Protocol{T}) where {T}
Return the external identifier associated with the protocol (e.g. it could be the host+port, dns name, ...)
Mango.init
— Methodinit(protocol::Protocol{T}, stop_check::Function, data_handler::Function) where {T}
Initialized the protocols internal loops (if exists). In most implementation this would mean that the receiver loop is started. To handle received messages the data_handler
function can be passed (msg, sender) -> your handling code
.
To control the lifetime of the loops a stop_check should be passed (() -> boolean). If the stop check is true the loops will terminate. The exact behavior depends on the implementation though.
Mango.notify_register
— Methodnotify_register(protocol::Protocol{T}, aid::String; kwargs...) where {T}
Protocol specific updates called when a new agent is registered.
Mango.parse_id
— Methodparse_id(protocol::Protocol{T}, id_data::Any)::T where {T}
Parse different types to the correct type (if required). Should be implemented if the id type is not trivial.
Mango.send
— Methodsend(protocol::Protocol{T}, destination::T, message::Any) where {T}
Send the message message
to the agent known by the adress destination
. How the message is exactly handled is determined by the protocol invoked.
The type of the destination has to match with the protocol. The function returns a boolean indicating whether the message was successfull sent
Mango.TCPProtocol
— TypeDefines the tcp protocol. It holds a binding to an IP+Port and a tcp connection pool.
Base.close
— Methodclose(pool::TCPConnectionPool)
Close the pool. This closes all connections. Further, this function will wait until all connection are released.
Base.close
— Methodclose(protocol::TCPProtocol)
Release all tcp resources (binding on port and connections in the pool).
Mango.acquire_tcp_connection
— Methodacquire_tcp_connection(tcp_pool::TCPConnectionPool, key::InetAddr)::Union{TCPSocket,Nothing}
Acquire a tcp connection from the pool for the key (IP+Port). Return a TCPSocket if the pool is not closed yet, otherwise nothing
will be returned
Mango.id
— Methodid(protocol::TCPProtocol)
Return the technical address of the protocol (ip + port)
Mango.init
— Methodinit(protocol::TCPProtocol, stop_check::Function, data_handler::Function)
Initialized the tcp protocol. This starts the receiver and stop loop. The receiver loop will call the data_handler with every incoming message. Further it provides as sender adress a InetAddr object.
Mango.parse_id
— Methodparse_id(_::TCPProtocol, id::Any)::InetAddr
Mango.release_tcp_connection
— Methodrelease_tcp_connection(
tcp_pool::TCPConnectionPool,
key::InetAddr,
connection::TCPSocket,
)
Release the given tcp connection
indexed by the key
. This will put the connection back to the pool.
Mango.send
— Methodsend(protocol::TCPProtocol, destination::InetAddr, message::Vector{UInt8})
Send a message message
over plain TCP using destination
as destination address. The message has to be provided as a form, which is writeable to an arbitrary IO-Stream.
Return true if successfull.
Simulation
In the following the APIs regarding the simulation container are listed.
Mango.SimulationContainer
— TypeThe SimulationContainer used as a base struct to enable simulations in Mango.jl. Shall be created using create_simulation_container
.
Mango.SimulationResult
— TypeResult of one simulation step.
Mango.TaskSimulationResult
— TypeResult of all task simulation iterations.
Mango.create_simulation_container
— Methodcreate_simulation_container(start_time::DateTime; communication_sim::Union{Nothing,CommunicationSimulation}=nothing, task_sim::Union{Nothing,TaskSimulation}=nothing)
Create a simulation container. The container is intitialized with start_time
.
Per default the SimpleCommunicationSimulation
is used for communication simulation, and SimpleTaskSimulation
for simulating the tasks of agents. To replace these, communication_sim
and respectively task_sim
can be set.
Mango.on_step
— Methodon_step(agent::Agent, world::World, clock::Clock, step_size_s::Real)
Hook-in, called on every step of the simulation container for every agent
.
Further, the world
is passed, which represents a common view on the environment in which agents can interact with eachother. Besides, the clock
and the step_size_s
can be used to read the current simulation time and the time which passes in the current step.
Mango.step_simulation
— Functionstep_simulation(container::SimulationContainer, step_size_s::Real=DISCRETE_EVENT)::Union{SimulationResult,Nothing}
Step the simulation using a continous time-span or until the next event happens.
For the continous simulation a step_size_s
can be freely chosen, for the discrete event type DISCRETEEVENT has to be set for the `stepsize_s`.
Mango.CommunicationSimulation
— TypeInterface to implement a communication simulation.
Mango.CommunicationSimulationResult
— TypeList of package results
Mango.MessagePackage
— TypeStruct describing a mesage between two agents.
Mango.PackageResult
— TypePackage result
Mango.SimpleCommunicationSimulation
— TypeDefault Implementation Communication Sim.
Implements a default delay which determines the delay of all messages if not specified in delay_s_directed_edge_dict
. The dict can contain a mapping (aidsender, aidreceiver) -> delay, such that the delay is specified for every link between agents.
Mango.calculate_communication
— Methodcalculate_communication(communication_sim::CommunicationSimulation, clock::Clock, messages::Vector{MessagePackage})::CommunicationSimulationResult
Calculate the communication using the specific communication simulation type. the current simulation time clock
and the message which shall be sent in this step messages
Mango.calculate_communication
— MethodImplementation for SimpleCommunicationSimulation
Mango.SimpleTaskSimulation
— TypeDefault implementation of the interface.
Mango.SimulationScheduler
— TypeSpecific scheduler, defined to be injected to the agents and intercept scheduling calls and especially the sleep calls while scheduling. This struct manages all necessary times and events, which shall fulfill the purpose to step the tasks only for a given step_size.
Mango.TaskIterationResult
— TypeDefine the result of an whole iteration of the task simulation
Mango.TaskResult
— TypeDefines the result of a task.
Mango.TaskSimulation
— TypeAbstract type to define a TaskSimulation
Mango.create_agent_scheduler
— Methodcreate_agent_scheduler(task_sim::TaskSimulation)
Create the scheduler used in the agents by the given task_sim
.
Mango.step_iteration
— Methodstep_iteration(task_sim::TaskSimulation, step_size_s::Real)::TaskIterationResult
Execute an iteration for a step of the simulation, which time is stepped with the step_size_s
.
Can be called repeatedly if new tasks are spawn as a result of other tasks or as result of arriving messages.
Scheduling
In the following the APIs for scheduling TaskData is listed.
Mango.AbstractScheduler
— TypeAbstract type for a scheduler
Mango.AwaitableTaskData
— TypeSchedule the function when the given awaitable
is finished. Can be used with any type for which wait
is defined.
Mango.Clock
— TypeDefault clock implementation, in which a static DateTime field is used.
Mango.ConditionalTaskData
— TypeSchedule the function when the condition
is fulfilled. To check whether it is fulfilled the condition function is called every check_interval_s
.
Mango.DateTimeTaskData
— TypeSchedule the function at a specific time determined by the date::DateTime.
Mango.InstantTaskData
— TypeInstant task data. Functions scheduled with this data is scheduled instantly.
Mango.PeriodicTaskData
— TypeTask data describing a periodic task.
A periodic task is defined by an interval_s
and optionally by a condition
. The interval determines how long the delay is between the recurring action. The condition is a stopping condition (no argument) which shall return true if the task shall stop.
Mango.Scheduler
— TypeDefault scheduler for the real time applications of Mango.jl.
Mango.TaskData
— TypeTaskData type, which is the supertype for all data structs, which shall describe a specific task type. Together with a new method execute task for the inherting struct, new types of tasks can be introduced.
Example
struct InstantTaskData <: TaskData end
function execute_task(f::Function, scheduler::AbstractScheduler, data::InstantTaskData)
f()
end
Base.schedule
— Methodschedule(f::Function, scheduler, data::TaskData)
Schedule a function (no arguments) using the specific scheduler (mostly the agent scheduler). The functino f
is scheduled using the information in data
, which specifies the way f
will be scheduled.
Mango.sleep_until
— Methodsleep_until(condition::Function)
Sleep until the condition (no args -> bool) is met.
Mango.stop_all_tasks
— Methodstop_all_tasks(scheduler::AbstractScheduler)
Stopps all stoppable tasks managed by scheduler
.
Mango.stop_and_wait_for_all_tasks
— Methodstop_and_wait_for_all_tasks(scheduler::AbstractScheduler)
Stopps all stoppable tasks and then wait for all tasks in scheduler
.
Mango.stop_task
— Methodstop_task(scheduler::AbstractScheduler, t::Task)
Stop the task t
managed by scheduler
. This only works if the task has been scheduled with the scheduler using a stoppable TaskData.
Mango.wait_for_all_tasks
— Methodwait_for_all_tasks(scheduler::AbstractScheduler)
Wait for all tasks managed by scheduler
.
Topology
In the following the APIs for creating, aplying and using topologies is listed.
Graphs.SimpleGraphs.add_edge!
— Functionadd_edge!(topology, node_id_from, node_id_to, directed=false)
Add an edge to the topology from node_id_from
to node_id_to
. If directed
is true a directed edge is added, otherwise an undirected edge is added.
Mango.add!
— Methodadd!(node, agent::Agent...)
Add an agents
to the node
.
Mango.add_node!
— Methodadd_node!(topology, agents::Agent...)::Int
Add a node to the topology with a list (or a single) of agents attached.
Mango.assign_agent
— Methodassign_agent(assign_condition::Function, topology::Topology, container::ContainerInterface)
Assign all agents of the container
to the nodes based on the given assign_condition
, this condition takes as Agent
and a Node
(node.id for the identifier of the node) and shall return a boolean indicating whether the agent shall be assigned to the node.
Mango.choose_agent
— Methodchoose_agent(choose_agent_function::Function, topology::Topology)
Choose the agents, which shall be assigned to the nodes. For this the choose_agent_function
has to be provided. This function expects Node
as argument and shall return an Agent
or Agent...
. The returned agent will be assigned to the node.
Mango.complete_topology
— Methodcomplete_topology(number_of_nodes)
Create a fully-connected topology.
Mango.create_topology
— Methodcreate_topology(create_runnable)::Topology
Create a topology using the create_runnable
function which is a one-argument function with an initially empty topology as argument.
Example
topology = create_topology() do topology
agent = register(container, TopologyAgent())
agent2 = register(container, TopologyAgent())
agent3 = register(container, TopologyAgent())
n1 = add_node!(topology, agent)
n2 = add_node!(topology, agent2)
n3 = add_node!(topology, agent3)
add_edge!(topology, n1, n2)
add_edge!(topology, n1, n3)
end
Mango.cycle_topology
— Methodcycle_topology(number_of_nodes)
Create a cycle topology.
Mango.graph_topology
— Methodgraph_topology(graph)
Create a topology based on a Graphs.jl (abstract) graph.
Mango.modify_topology
— Methodmodify_topology(modify_runnable::Functino, topology::Topology)
Modify a topology using the modify_runnable
function which is a one-argument function with the provided topology as argument.
Example
modify_topology(my_topology) do topology
agent = register(container, TopologyAgent())
agent2 = register(container, TopologyAgent())
agent3 = register(container, TopologyAgent())
n1 = add_node!(topology, agent)
n2 = add_node!(topology, agent2)
n3 = add_node!(topology, agent3)
add_edge!(topology, n1, n2)
add_edge!(topology, n1, n3)
end
Mango.per_node
— Methodper_node(assign_runnable, topology)
Loops over the nodes of the topology
, calls assign_runnable
on every node to enable the caller to populate the node. After the loop finished the neighborhoods are created and injected into the agent.
Example
per_node(topology) do node
add!(node, register(container, TopologyAgent()))
end
Mango.remove_edge!
— Methodremove_edge!(topology::Topology, node_id_from::Int, node_id_to::Int)
Remove the edge between node_id_from
and node_id_to
.
Mango.remove_node!
— Methodremove_node!(topology::Topology, node_id::Int)
Remove the node with the id node_id
.
Mango.set_edge_state!
— Methodset_state!(topology::Topology, node_id_from::Int, node_id_to::Int, state::State)
Set the state of the state of the edge (node_id_from, node_id_to)
to state
.
Mango.star_topology
— Methodstar_topology(number_of_nodes)
Create a star topology.
Mango.topology_neighbors
— Functiontopology_neighbors(agent)
Retrieve the neighbors of the agent
, represented by their addresses. These vaues will be updated when a topology is applied using per_node
or create_topology
.
Encoding/Decoding
In the following the built-in functions for encoding and decoding messages are listed.
Mango.decode
— Functiondecode(buf::Vector{UInt8}, t::Type=OrderedDict{String, Any})
Decode the data in buf
into an object of type t
using LightBSON.bson_read
.
Examples
julia> data = OrderedDict(["test" => 10])
OrderedDict{String, Int64} with 1 entry:
"test" => 10
julia> decode(encode(data))
OrderedDict{String, Any} with 1 entry:
"test" => 10
Mango.encode
— Methodencode(data::OrderedDict{String,Any})
Encode data
into a UInt8 buffer using LightBSON.
Examples
julia> data = OrderedDict(["test" => 10])
OrderedDict{String, Int64} with 1 entry:
"test" => 10
julia> encode(data)
19-element Vector{UInt8}:
0x13
0x00
0x00
0x00
0x12
⋮
0x00
0x00
0x00
0x00
0x00
Misc
Mango.@with_def
— MacroThis macro can be applied to struct definitions and adds the possibility to define default values on field declaration. In contrast to @kwdef or @with_kw, this macro will create normal parameters for construction if no default value has been provided.
Example
@with_def struct ExampleStruct
abc::Int = 0
def::String
end
# can be constructed as follows
es = ExampleStruct("mydefstring") # abc == 0
es = ExampleStruct("mydefstring", abc=3) # abc == 3