We tried to deprecate every major change, resulting in practically no breakage from v5 to v6. However, in version v6.2 we will remove all deprecations (and hence un-updated code will break)
- The
@agent
macro has been rewritten to support fields with default and const values. It has a new usage syntax now that parallelizes more Julia's nativestruct
declaration. The old macro version still works but it's deprecated. Since now the macro supports these features, using@agent
is the only supported way to create agent types for Agents.jl. - Manually setting or altering the ids of agents is no longer allowed. The agent id is now considered a read-only field, and is set internally by Agents.jl to enable hidden optimizations in the future. Due to this, the
nextid
function is no longer public API. As a consequence, new constructor of agents which accept the model as first argument have been created with the agent macro e.g.A(model, pos; kwargs...)
, so that to handle the id assignment automatically.- We anyways recommend using exclusively the API function
add_agent!
to create new model agents. This means you never have to care about the id!
- We anyways recommend using exclusively the API function
- Agent types in
ContinuousSpace
now useSVector
for theirpos
andvel
fields rather thanNTuple
.NTuple
usage inContinuousSpace
is officially deprecated, but backward compatibility is mostly maintained. Known breakages include the comparison of agent position and/or velocity with user-defined tuples, e.g., doingagent.pos == (0.5, 0.5)
. This will always befalse
in v6 asagent.pos
is anSVector
. The rest of the functionality should all work without problems, such as moving agents to tuple-based positions etc. - The
:step
column name of the dataframes resulting fromrun!
has been renamed to:time
, to accommodate for the fact that now both discrete time and continuous time models are possible in Agents.jl.
AgentBasedModel
defines an API that new model types may extend. This opens the door for making new types of models as well as better integration of other agent based modelling frameworks with Agents.jl.- Every aspect of Agents.jl is orthogonal to
AgentBasedModel
: movement and neighbor searching in any space, data collection, visualizations, etc., are independent of the specific type ofAgentBasedModel
and work out of the box with any model. - Logic of when to collect data in
run!
has been improved to accommodate both discrete and continuous time models. This is reflected in the new options for the keywordwhen
.- A new keyword
init
is now available forrun!
to data collect from the model before evolving it. Whether data were collected at time 0 or not was not really obvious in the original version ofrun!
due to the ambiguity of the previous handling ofwhen
.
- A new keyword
- A new
@multiagent
macro allows to run multi-agent simulations much more efficiently. It has two version: In:opt_speed
the created agents are optimized such as there is virtually no performance difference between having 1 agent type at the cost of each agent occupying more memory that in theUnion
case. In:opt_memory
each agent is optimized to occupy practically the same memory as theUnion
case, however this comes at a cost of performance versus having 1 type. - A new experimental model type
EventQueueABM
has been implemented. It operates in continuous time through the scheduling of events at arbitrary time points, in contrast with the discrete time nature of aStandardABM
. - Both the visualization and the model abstract interface have been refactored to improve the user experience to conform to the Agents.jl API when creating a new model type and its visualizations.
- Grid and continuous spaces support boundaries with mixed periodicity, specified by tuples with a
Bool
value for each dimension, e.g.GridSpace((5,5); periodic=(true,false))
is periodic along the first dimension but not along the second. Arrow
backend inoffline_run!
is now supported also for Windows users.- The model time is now tracked automatically, accessible through
abmtime(model)
. This is part of the newAgentBasedModel
API. - Two new functions
random_id_in_position
andrandom_agent_in_position
can be used to select a random id/agent in a position in discrete spaces (even with filtering). - A new function
swap_agents
can be used to swap the positions of a pair of agents, which works even in spaces which allow 1 agent per position. - New function
hasid
to check if a model has an agent with a given id.
- A new argument
alloc
can be used to select a more performant version in relation to the expensiveness of the filtering for all random methods selecting ids/agents/positions. - The
random_agent
function is now much faster than before. The functionsrandom_nearby_position
,random_nearby_id
andrandom_nearby_agent
are much faster thanks to a faster sampling function. - The
nearby_agents
function forContinuousSpace
andGridSpace
is now 1.5x faster than before. - The
sample!
function is much faster than before.
- The way the evolution rule (
agent_step!, model_step!
) is handled has changed. Now, the stepping functions must be given to the agent based model during construction of the model instead of given tostep!, run!, abmplot, ...
. This change is important and allows us to:- Have Agents.jl have the same mental model as DifferentialEquations.jl, DynamicalSystems.jl, and other dynamical modelling packages, where the evolution rules are part of the central simulation struct.
- Allows us to develop new types of models that may have rules that are defined differently, without being based on e.g., two particular functions.
- Allows us to develop (in the future) a new model type that is optimized for multi-agent simulations.
- Allows other developers of agent based modelling packages to integrate with Agents.jl by extending the established API.
- The
UnremovableABM
type is deprecated, insteadcontainer = Vector
should be passed when creating the model. - Passing the
step
argument tocollect_model_data!, collect_agent_data!
is deprecated since the time of the model is used automatically. add_agent_pos!
has been deprecated in favor of the more descriptiveadd_agent_own_pos!
.schedule(model, scheduler)
is deprecated. Usescheduler(model)
together withhasid(model)
.- Deprecations that were in place in v5 (see section
# v5
of this CHANGELOG) have been removed. - Keyword
spf
is deprecated in favor ofdt
inabmvideo
.
- New function
replicate!
allows to create a new instance of a given agent at the same position with the possibility to specify some fields with new values. - The
sample!
function is 3x faster than before.
- New function
offline_run!
allows writing data to file at predefined intervals duringrun!
instead of storing it in memory. Currently supports CSV and Arrow files.
- Agents.jl moved to Julia 1.9+, and now exports visualization and interactive applications automatically once Makie (or Makie backends such as GLMakie) come into scope, using the new package extension system. The only downside of this is that now to visualize ABMs on open street maps, the package OSMMakie.jl must be explicitly loaded as well.
- Nearby look-ups with
nearby_positions
,nearby_ids
and derivatives are now incrementally faster than before more the radius increases. - The
randomwalk!
function is now supported for any number of dimensions in ContinuousSpace when used to create isotropic/uniform random walks. For all type ofAbstractGridSpace
, therandomwalk!
function supports a new keywordforce_motion
, which is false by default. See the docs to be informed on the effect of setting this keyword. Besides, in the continuous space default case random walks are up to 2 times faster than before. - Adding agents through
properties...
is an order of magnitude faster, now matching the performance of the other versions. - The
ByProperty
scheduler can now accept any type of (ordered) properties, while before it was restricted to only floats. TheByID
scheduler of anUnremovableABM
is now as fast as theFastest
scheduler since in this case they are actually equivalent.
- New optional filtering functionality to restrict the sampling added to
random_nearby_position
,random_nearby_id
andrandom_nearby_agent
.
random_nearby_position
,random_nearby_id
andrandom_nearby_agent
are up to 2 times faster thanks to a faster sampling function.
- The
random_nearby_position
function is now much faster for GridSpaces.
- Iterating in neighborhood searches (with
nearby_ids
and derivative functions) inGridSpace
andContinuousSpace
is now about 2 times faster than before.
FixedMassABM
is now deprecated and will be removed in future versions. Turns out, there is no performance benefit of using it overUnremovableABM
. In fact, there is a performance deficit in doing so.
sample!
is now much faster than before when the size of the sample is big, with a size of 1 million agents the function is now 1000x faster.- A memory bug about offsets calculation has been solved; besides, the
calculate_offsets
function has been sped-up by a significant amount. - The following renames have been done (with deprecations):
genocide! -> remove_all!
kill_agent! -> remove_agent!
UnkillableABM -> UnremovableABM
- New function
random_nearby_position
that returns a random neighbouring position. - New function
empty_nearby_positions
that returns an iterable of all empty neighboring positions.
random_agent
is now faster and has two options on how to find a random agent, each of which can offer a different performance benefit depending on the density of agents that satisfy the clause.- New function
randomwalk!
replaceswalk!(agent, rand, model)
(now deprecated), allowing easier creation of random walks in both discrete and continuous spaces. Random walks in continuous space also allow users to specify the reorientation distributions:polar
in 2D;polar
andazimuthal
in 3D. This way, correlated random walks can be produced. - Thanks to the use of a new algorithm, the
nearby_positions
function for graphspaces is now much faster. - Huge improvement of performance of the
get_direction
function in the periodic case. normalize_position
is now 50x faster for the case of a non-periodic grid.
- Internals of
AgentBasedModel
got reworked. It is now an abstract type, defining an abstract interface that concrete implementations may satisfy. This paves the way for flexibly defining new variants ofAgentBasedModel
that are more specialized in their applications. - The old
AgentBasedModel
is nowStandardABM
. - Two new variants of agent based models:
UnkillableABM
andFixedMassABM
: they yield huge performance benefits (up to twice the speed!!!) on iterating over agents if the agents can't get killed, or even added, during model evolution! - Huge memory performance increase in continuous space by fixing a memory leak bug.
multi_agents_type!
has been updated to handle edge case where agents of one (or more) type are absent at the beginning of the simulation.- New function
npositions
that returns the number of positions of a model with a discrete space.
add_node!
andrem_node!
have been renamed toadd_vertex!
andrem_vertex!
extending Graphs.jl homonymous methods to help standardise names across ecosystems. Thereforeadd_node!
andrem_node!
have been deprecated.- The signature of
add_edge!
has been generalised withargs...
andkwargs...
to be compatible with all the implementations the underlying graph supports. - New function
rem_edge!
that removes an edge from the graph.
- The
@agent
macro has been re-written and is now more general and more safe. It now also allows inheriting fields from any other type. - The
@agent
macro is now THE way to create agent types for Agents.jl simulations. Directly creating structs by hand is no longer mentioned in the documentation at all. This will allow us in the future to utilize additional fields that the user does not have to know about, which may bring new features or performance gains by being part of the agent structures.- EDIT: This has been retracted in future versions.
@agent
is the recommended way, but manual creation is also valid.
- EDIT: This has been retracted in future versions.
- The minimal agent types like
GraphAgent
can be used normally as standard agent types that only have the mandatory fields. This is now clear in the docs. (this was possible also before v5.4, just not clear) - In the future, making agent types manually (without
@agent
) may be completely disallowed, resulting in error. Therefore, making agent types manually is considered deprecated. - New function
normalize_position
that normalizes a position according to the model space. - New function
spacesize
that returns the size of the space.
This is a huge release!
- Internal representation of grid spaces has been completely overhauled. For
GridSpace
this lead to about 30% performance increase innearby_stuff
and 100% decrease in memory allocations. - Significant performance increase for
nearest_neighbor
inContinuousSpace
. - Because of the new grid spaces internals,
nearby_stuff
searches inContinuousSpace
are 2-5 times faster. - Much more efficient distributed computing in
ensemblerun!
andparamscan
functions, like 5x performance gain. Thanks to user Matt Turnermt-digital
. #624
- New space
GridSpaceSingle
that is the same asGridSpace
but only allows for one agent per position only. It utilizes this knowledge for massive performance benefits overGridSpace
, being about 3x faster than the newGridSpace
, all across the board. ID = 0 is a reserved ID for this space and cannot be used by users.
- New keyword
showprogress
inrun!
function that displays a progress bar. - New keyword
showprogress
inensemblerun!
andparamscan
that displays a progress bar over total amount of simulations done. - New function
OSM.route_length
. - New
:manhattan
metric forGridSpace
models. - New
manhattan_distance
utility function. - New keyword
nearby_f = nearby_ids_exact
ininteracting_pairs
which decides whether to use the exact or approximate algorithm for nearest neighbors.
- [Will be breaking] In the near future, agent ID = 0 will be a reserved ID by Agents.jl. This means that users should not use ID = 0 for any agent. They can use all the negative and positive integers as usual. If you were adding agents with any of the default ways that Agents.jl provides, such as
add_agents!(pos, model, agent_properties...)
, then you were already using only the positive integers. - [Maybe breaking?] In
ContinuousSpace
spacing
was documented to be a keyword but in code it was specified as a positional argument. Now it is also a keyword in code as intended. - [Maybe breaking?] Keyword
spacing
inContinuousSpace
is nowminimum(extent)/20
from/10
by default, increasing accuracy ofnearby_ids
(which is the fastest way to iterate over neighbors). This decreases a bit the performance ofmove_agent!
, but in the typical scenario a neighbor search is much more costly than moving an agent. - [Maybe breaking?] There was an ambiguity in the function
move_agent!(agent, model)
. It typically means to move an agent to a random position. However, inContinuousSpace
this function was overwritten by the signaturemove_agent(agent, model, dt::Real = 1)
. To resolve the ambiguity, nowmove_agent!(agent, model)
always moves the agent to a random position even inContinuousSpace
. To use the continuous space version that moves an agent using its velocity, users must explicitly provide the third argumentdt
. - [Will be breaking] Keyword
exact
innearby_ids
forContinuousSpace
is deprecated, because now the exact version returns different type than the non-exact, hence leading to type instabilities. Usenearby_ids_exact
instead. Same fornearby_agents
.
- Rework schedulers to prefer returning iterators over arrays, resulting in fewer allocations and improved performance. Most scheduler names are now types instead of functions:
Schedulers.by_id
is nowSchedulers.ByID
Schedulers.randomly
is nowSchedulers.Randomly
Schedulers.partially
is nowSchedulers.Partially
Schedulers.by_property
is nowSchedulers.ByProperty
Schedulers.by_type
is nowSchedulers.ByType
- Add
random_nearby_id
andrandom_nearby_agent
for efficient random agent access - Stop condition for
step!
allows usingInteger
s
- Agents.jl + InteractiveDynamics.jl now support native plotting for open street map spaces, which is integrated in all interactive apps as well!
- Most examples have been moved to AgentsExampleZoo.jl. Additional examples will now be added there.
- Plotting, animating, and interacting GUIs based on InteractiveDynamics.jl have changed. Please see online docs for the new format.
- LightGraphs.jl dependency is now replaced by Graphs.jl
- OpenStreetMapX.jl dependency now replaced by LightOSM.jl. This mean initializing the space is different, and some API methods have changed. Check documentation for more details. Note that this also means checkpoints using the old
OpenStreetMapSpace
cannot be read in this version. - Functions for planning and moving along routes have had their names unified across Pathfinding and OpenStreetMap modules. The names now are
plan_route!
andmove_along_route!
and are accessible from the top level scope. OSM.intersection
is renamed toOSM.nearest_node
OSM.road
is renamed toOSM.nearest_road
latlon
is removed in favor ofOSM.lonlat
- Previously
nearby_ids
withr=0
forGraphSpace
was undefined. Now it returns ids only in the same position as given.
- Performance enhancements for
random_empty
.
- Add
get_spatial_property
andget_spatial_index
for easier usage of spatially distributed properties inContinuousSpace
. - Rework the pathfinding system to be more streamlined and offer greater control over the its details.
- Add support for pathfinding in
ContinuousSpace
. - New utility functions
nearby_walkable
andrandom_walkable
for use in models with pathfinding. - Fixed bug where there was no differentiation between empty paths and paths to unreachable nodes.
- The old pathfinding system is now deprecated. Pathfinding structs are not saved as part of the space, and instead are stored by the user.
- Provide a generator function to collect
mdata
inrun!
andensemblerun!
. - Save/load entire models using
save_checkpoint
andload_checkpoint
- New functions
get_spatial_property
andget_spatial_index
that allows better handling of spatial fields present inContinuousSpace
that are represented via the forms of discretization over the space.
- Save and load agent information from CSV files.
- Self-contained features of Agents.jl will from now own exist in their own submodules. This will make the public API less cluttered and functionality more contained. Currently the new submodules are
Schedulers, Pathfinding, OSM
. - Pathfinding using the A* algorithm is now possible! Available for
GridSpace
. - Extend
dataname
(formerlyaggname
) to provide unique column names in collection dataframes when using anonymous functions - Fixed omission which did not enable updating properties of a model when
model.properties
is astruct
. - New function
ensemblerun!
for running ensemble model simulations. - Scheduler
Schedulers.by_property
(previouslyproperty_activation
) now allows as input arbitrary functions besides symbols.
- Deprecate
aggname
in favor ofdataname
for naming of columns in collection dataframes - Keyword
replicates
ofrun!
is deprecated in favor ofensemblerun!
. paramscan
withreplicates
is deprecated. If you want to parameter scan and at the same time run multiple simulations at each parameter combination, simply useseed
as a parameter, which tunes the model's initial random seed.- All the scheduler names have been deprecated in favor of a
Schedulers
module:fastest
toSchedulers.fastest
,by_id
toSchedulers.by_id
,random_activation
toSchedulers.randomly
,partial_activation
toSchedulers.partially
,property_activation
toSchedulers.by_property
,by_type
toSchedulers.by_type
.
- Plotting with Plots.jl and
plotabm
is deprecated in favor of InteractiveDynamics.jl, Makie.jl andabm_plot
.
- A new example: Fractal Growth, explores
ContinuousSpace
and interactive plotting. - Models now supply a random number generator pool that is used in all random-related functions like
random_position
. Access it withmodel.rng
and seed it withseed!(model, seed)
. - Higher-order agent grouping utilities to facilitate complex interactions, see e.g.
iter_agent_groups
. - Several documentation improvements targeting newcomers.
This new release brings not only a lot of new features but also a lot of performance improvements and quality of life improvements. Worth seeing is also the new Comparison section of our docs, which compares Agents.jl with other existing software, showing that Agents.jl outmatches all current standards.
GridSpace
has been re-written from scratch! It now supports any dimensionality and is about a full order of magnitude faster than the previous version!ContinuousSpace
has been re-written from scratch! It is now at least 3 times faster!- A new, continuous
OpenStreetMapSpace
which lets agents traverse real world locations via planned routes based on the Open Street Map initiative. GraphSpace
now allows to dynamically mutate the underlying graph viaadd_node!
,rem_node!
.- Agents.jl now defines a clear API for new spaces types. To create a fundamentally different type of space you have to define the space structure and extend only 5 methods.
GraphSpace
andGridSpace
are completely separated entities, reducing complexity of source code dramatically, and removing unnecessary functions likevertex2coord
andcoord2vertex
.- Many things have been renamed to have clearer name that indicates their meaning (see Breaking changes).
- Performance increase of finding neighbors in GraphSpace with r > 1.
- New wrapping function
nearby_agents
that returns an iterable of neighboring agents. - Positions and neighbors on
GridSpace
can now be searched in each direction separately by acceptingr
as a tuple. - Neighbors on non-periodic chebyshev spaces can also be searched per dimension over a specific range.
- New public
schedule
function for writing custom loops. - Mixed models are supported in data collection methods.
random_agent(model, condition)
allows obtaining random agents that satisfy given condition.- New
walk!
utility function forGridSpace
andContinuousSpace
s, providing turtle-like agent movement and random walks. - The Battle Royal example explores using categorical neighbor searching in a high dimensional
GridSpace
. - An
@agent
macro provides a quick way of creating agent structs for any space.
Most changes in this section (besides changes to default values) are deprecated and therefore are not "truly breaking".
- New
ContinuousSpace
now only supports Euclidean metric. - Keyword
moore
ofGridSpace
doesn't exist anymore. Usemetric
instead. - Default arguments for
GridSpace
are nowperiodic = true, metric = :chebyshev
. - Internal structure of the fundamental types like
ABM, GraphSpace
, etc. is now explicitly not part of the public API, and the provided functions likegetindex
andgetproperty
have to be used. This will allow performance updates in the future that may change internals but not lead to breaking changes. vertex2coord, coord2vertex
do not exist anymore because they are unnecessary in the new design.- API simplification and renaming:
space_neighbors
->nearby_ids
node_neighbors
->nearby_positions
get_node_contents
->ids_in_position
get_node_agents
->agents_in_position
pick_empty
->random_empty
find_empty_nodes
->empty_positions
has_empty_nodes
->has_empty_positions
nodes
->positions
GridSpace
agents now useDims
rather thanTuple{N,Int}
for theirpos
ition in all examples and pre-defined models.
- Add the ability to decide whether the agent step or the model step should be performed first using the
agents_first
argument.
- Add ability to customise
run!
such that mutation on containers and nested structures does not affect data collection.
- Aggregation data for agents is now possible to do conditionally.
- Example on how to integrate Agents.jl with BlackBoxOptim.jl.
- Added interactivity examples for Schelling and Daisyworld.
- Example on how to integrate Agents.jl with DifferentialEquations.jl.
- Dropped support for Julia 1.0, will be targeting LTS for v1.6 in the future.
- New
fill_space!
function for discrete spaces. - The Daisyworld example now uses multi-agent approach (surface is agent).
- New
allids
function.
- New
Models
submodule, that conveniently allows loading a model from the examples.
- Extend
interacting_pairs
to allow interactions of disparate types when using mixed models.
- Added
ContinuousSpace
as a space option. Supports Euclidean and Cityblock metrics. Several new API functions were added for continuous space. - Universal plotting function
plotabm
that works for models with any kind of space. - new function
space_neighbors
, which works for any space. It always and consistently returns the IDs of neighbors irrespectively of the spatial structure. AgentBasedModel
now allows you to pass in anAbstractAgent
type, or an instance of your agent.- New convenience function
allagents
. - New continuous space functions
nearest_neighbor
andelastic_collision!
. - New iterator
interacting_pairs
. - Agents can be accessed from the model directly.
model[id]
is equivalent withmodel.agents[id]
and replacesid2agent
. - If
model.properties
is a dictionary with key type Symbol, then the convenience syntaxmodel.prop
returnsmodel.properties[:prop]
. - Version of
add_agent!
now has keyword propagation as well (in case you make your types with@kwdef
or Parameters.jl). - New function
nextid
- Cool new logo.
node_neighbors
now accepts aneighbor_type
keyword for working with directed graphs.- Added examples of flocking birds and bacterial growth in
ContinuousSpace
, daisyworld and predator-prey inGridSpace
.
- Collection of model and agent data simultaneously is now possible using the
mdata
andadata
keywords (respectively) used in conjunction with the revamped data collection scheme (see below). - Better support for mixed-ABMs and a new
by_type
scheduler.
- Deprecated
Space
in favor of the individual spaces:Nothing, GridSpace, GraphSpace, ContinuousSpace
. - Reworked the public API of
GridSpace
to be simpler: position must beNTuple{Int}
. As a resultvertex2coord
and stuff no longer exported, since they are obsolete.
- Data collection has been completely overhauled. The main function to evolve an ABM and collect data is now
run!
. This function serves most situations, however multiple low level functions are exposed via the API for power users. See the Data Collection section in the documentation for full details. AgentBasedModel
checks the construction of your agent and will return errors when it is malformed (noid
orpos
when required, incorrect types). Warnings when possible problems may occur (immutable agents, types which are not concrete,vel
not of the correct type when usingContinuousSpace
).id2agent
is deprecated in favor ofgetindex(model, id) == model[id]
.
- Function
plot2D
doesn't exist any more in favor ofplotabm
.
- Renamed the old scheduler
as_added
toby_id
, to reflect reality. - Added a scheduler public API.
- Added two new schedulers:
partial_activation
,property_activation
. - It is now possible to
step!
until a boolean condition is met.
Changelog is kept with respect to version 2.0.