Developer Docs

Cloning the repository

Since we include documentation with many animated gifs and videos in the repository, a standard clone can be larger than expected. If you wish to do any development work, it is better to use

git clone https://github.com/JuliaDynamics/Agents.jl.git --single-branch

Creating a new space type

Creating a new space type within Agents.jl is quite simple and requires the extension of only 5 methods to support the entire Agents.jl API. The exact specifications on how to create a new space type are contained within the file: [src/core/space_interaction_API.jl].

In principle, the following should be done:

  1. Think about what the agent position type should be.
  2. Think about how the space type will keep track of the agent positions, so that it is possible to implement the function nearby_ids.
  3. Implement the struct that represents your new space, while making it a subtype of AbstractSpace.
  4. Extend random_position(model).
  5. Think about how the positions of agents will be updated as agents are moved, added or killed.
  6. Extend add_agent_to_space!(agent, model), remove_agent_from_space!(agent, model).
  7. Extend nearby_ids(position, model, r).

And that's it! Every function of the main API will now work. In some situations you might want to explicitly extend other functions such as move_agent! for performance reasons.

Designing a new Pathfinder Cost Metric

To define a new cost metric, simply make a struct that subtypes CostMetric and provide a delta_cost function for it. These methods work solely for A* at present, but will be available for other pathfinder algorithms in the future.

Agents.Pathfinding.CostMetricType
Pathfinding.CostMetric{D}

An abstract type representing a metric that measures the approximate cost of travelling between two points in a D dimensional grid.

source
Agents.Pathfinding.delta_costFunction
Pathfinding.delta_cost(pathfinder::GridPathfinder{D}, metric::M, from, to) where {M<:CostMetric}

Calculate an approximation for the cost of travelling from from to to (both of type NTuple{N,Int}. Expects a return value of Float64.

source

Implementing custom serialization

For model properties

Custom serialization may be required if your properties contain non-serializable data, such as functions. Alternatively, if it is possible to recalculate some properties during deserialization it may be space-efficient to not save them. To implement custom serialization, define methods for the to_serializable and from_serializable functions:

Agents.AgentsIO.to_serializableFunction
AgentsIO.to_serializable(t)

Return the serializable form of the passed value. This defaults to the value itself, unless a more specific method is defined. Define a method for this function and for AgentsIO.from_serializable if you need custom serialization for model properties. This also enables passing keyword arguments to AgentsIO.load_checkpoint and having access to them during deserialization of the properties. Some possible scenarios where this may be required are:

  • Your properties contain functions (or any type not supported by JLD2.jl). These may not be (de)serialized correctly. This could result in checkpoint files that cannot be loaded back in, or contain reconstructed types that do not retain their data/functionality.
  • Your properties contain data that can be recalculated during deserialization. Omitting such properties can reduce the size of the checkpoint file, at the expense of some extra computation at deserialization.

If your model properties do not fall in the above scenarios, you do not need to use this function.

This function is not called recursively on every type/value during serialization. The final serialization functionality is enabled by JLD2.jl. To define custom serialization for every occurence of a specific type (such as agent structs), refer to the Custom Serialization section of JLD2.jl documentation.

source
Agents.AgentsIO.from_serializableFunction
AgentsIO.from_serializable(t; kwargs...)

Given a value in its serializable form, return the original version. This defaults to the value itself, unless a more specific method is defined. Define a method for this function and for AgentsIO.to_serializable if you need custom serialization for model properties. This also enables passing keyword arguments to AgentsIO.load_checkpoint and having access to them through kwargs.

Refer to AgentsIO.to_serializable to check when you need to define this function.

This function is not called recursively on every type/value during deserialization. The final serialization functionality is enabled by JLD2.jl. To define custom serialization for every occurence of a specific type (such as agent structs), refer to the Custom Serialization section of JLD2.jl documentation.

source

For agent structs

Similarly to model properties, you may need to implement custom serialization for agent structs. from_serializable and to_serializable are not called during (de)serialization of agent structs. Instead, JLD2's custom serialization functionality should be used. All instances of the agent struct will be converted to and from the specified type during serialization. For OpenStreetMap agents, the position, destination and route are saved separately. These values will be loaded back in during deserialization of the model and override any values in the agent structs. To save space, the agents in the serialized model will have empty route fields.