Changelog

0.1.5 (December 2021)

  • Experiment.run() has a new argument ‘n_jobs’ that allows for parallel processing with joblib.Parallel().

  • Two new methods - Grid.record_positions() and Space.record_positions() - can be used to record agent positions.

  • Model.run() can now continue simulations that have already been run. The steps defined in the argument ‘steps’ now reflect additional steps, which will be added to the models current time-step. Random number generators will not be re-initialized in this case.

  • animate() has been improved. It used to stop the animation one step too early, which has been fixed. Two faulty import statements have been corrected. And, as above, the argument ‘steps’ now also reflects additional steps.

  • Grid.add_field() has been fixed. Single values can now be passed.

0.1.4 (September 2021)

0.1.3 (August 2021)

  • The Grid functionality track_empty has been fixed to work with multiple agents per cell.

  • Getting and setting items in AttrIter has been fixed.

  • Sequences like AgentList and AgentDList no longer accept args, only kwargs. These keyword arguments are forwarded to the constructor of the new objects. Keyword arguments with sequences of type AttrIter will be broadcasted, meaning that the first value will be assigned to the first object, the second to the second, and so forth. Otherwise, the same value will be assigned to all objects.

0.1.2 (June 2021)

  • The property Network.nodes now returns an AttrIter, so that network nodes can be assigned to agents as follows:

    self.nw = ap.Network(self)
    self.agents = ap.AgentList(self, 10)
    self.nw.add_agents(self.agents)
    self.agents.node = self.nw.nodes
    
  • AgentIter now requires the model to be passed upon creation and has two new methods AgentIter.to_list() and AgentIter.to_dlist() for conversion between sequence types.

  • Syntax highlighting in the documentation has been fixed.

0.1.1 (June 2021)

  • Marked release for the upcoming JOSS publication of AgentPy.

  • Fixed Grid.move_to(): Agents can now move to their current position.

0.1.0 (May 2021)

This update contains major revisions of most classes and methods in the library, including new features, better performance, and a more coherent syntax. The most important API changes are described below.

Object creation

The methods add_agents(), add_env(), etc. have been removed. Instead, new objects are now created directly or through Sequences. This allows for more control over data structures (see next point) and attribute names. For example:

class Model(ap.Model):
    def setup(self):
        self.single_agent = ap.Agent()  # Create a single agent
        self.agents = ap.AgentList(self, 10)  # Create a sequence of 10 agents
        self.grid = ap.Grid(self, (5, 5))  # Create a grid environment

Data structures

The new way of object creation makes it possible to choose specific data structures for different groups of agents. In addition to AgentList, there is a new sequence type AgentDList that provides increased performance for the lookup and deletion of agents. It also comes with a method AgentDList.buffer() that allows for safe deletion of agents from the list while it is iterated over

AttrList has been replaced by AttrIter. This improves performance and makes it possible to change agent attributes by setting new values to items in the attribute list (see AgentList for an example). In most other ways, the class still behaves like a normal list. There are also two new classes AgentIter and AgentDListIter that are returned by some of the library’s methods.

Environments

The three environment classes have undergone a major revision. The add_agents() functions have been extended with new features and are now more consistent between the three environment classes. The method move_agents() has been replaced by move_to() and move_by(). Grid is now defined as a structured numpy array that can hold field attributes per position in addition to agents, and can be customized with the arguments torus, track_empty, and check_border. gridplot() has been adapted to support this new numpy structure. Network now consists of AgentNode nodes that can hold multiple agents per node, as well as node attributes.

Environment-agent interaction

The agents’ env attribute has been removed. Instead, environments are manually added as agent attributes, giving more control over the attribute name in the case of multiple environments. For example, agents in an environment can be set up as follows:

class Model(ap.Model):
    def setup(self):
        self.agents = ap.AgentList(self, 10)
        self.grid = self.agents.mygrid = ap.Grid(self, (10, 10))
        self.grid.add_agents(self.agents)

The agent methods move_to, move_by, and neighbors have also been removed. Instead, agents can access these methods through their environment. In the above example, a given agent a could for example access their position through a.mygrid.positions[a] or their neighbors through calling a.mygrid.neighbors(a).

Parameter samples

Variable parameters can now be defined with the three new classes Range (for continuous parameter ranges), IntRange (for integer parameter ranges), and Values (for pre-defined of discrete parameter values). Parameter dictionaries with these classes can be used to create samples, but can also be passed to a normal model, which will then use default values. The sampling methods sample(), sample_discrete(), and sample_saltelli() have been removed and integrated into the new class Sample, which comes with additional features to create new kinds of samples.

Random number generators

Model now contains two random number generators Model.random and Model.nprandom so that both standard and numpy random operations can be used. The parameter seed can be used to initialize both generators. Sample has an argument randomize to vary seeds over parameter samples. And Experiment has a new argument randomize to control whether to vary seeds over different iterations. More on this can be found in Randomness and reproducibility.

Data analysis

The structure of output data in DataDict has been changed. The name of measures has been changed to reporters. Parameters are now stored in the two categories constants and sample. Variables are stored in separate dataframes based on the object type. The dataframe’s index is now separated into sample_id and iteration. The function sensitivity_sobol() has been removed and is replaced by the method DataDict.calc_sobol().

Interactive simulations

The method Experiment.interactive() has been removed and is replaced by an interactive simulation interface that is being developed in the separate package ipysimulate. This new package provides interactive javascript widgets with parameter sliders and live plots similar to the traditional NetLogo interface. Examples can be found in Interactive simulations.

0.0.7 (March 2021)

Continuous space environments

A new environment type Space and method Model.add_space() for agent-based models with continuous space topologies has been added. There is a new demonstration model Flocking behavior in the model library, which shows how to simulate the flocking behavior of animals and demonstrates the use of the continuous space environment.

Random number generators

Model has a new property Model.random, which returns the models’ random number generator of type numpy.random.Generator(). A custom seed can be set for Model.run() and animate() by either passing an argument or defining a parameter seed. All methods with stochastic elements like AgentList.shuffle() or AgentList.random() now take an optional argument generator, with the model’s main generator being used if none is passed. The function AgentList.random() now uses numpy.random.Generator.choice() and has three new arguments ‘replace’, ‘weights’, and ‘shuffle’. More information with examples can be found in the API reference and the new user guide Randomness and reproducibility.

Other changes

  • The function sensitivity_sobol() now has an argument calc_second_order (default False). If True, the function will add second-order indices to the output.

  • The default value of calc_second_order in sample_saltelli() has also been changed to False for consistency.

  • For consistency with Space, Grid no longer takes an integer as argument for ‘shape’. A tuple with the lengths of each spatial dimension has to be passed.

  • The argument ‘agents’ has been removed from Environment. Agents have to be added through Environment.add_agents().

Fixes

0.0.6 (January 2021)

  • A new demonstration model Segregation has been added.

  • All model objects now have a unique id number of type int. Methods that take an agent or environment as an argument can now take either the instance or id of the object. The key attribute of environments has been removed.

  • Extra keyword arguments to Model and Experiment are now forwarded to Model.setup().

  • Model.run() now takes an optional argument steps.

  • EnvDict has been replaced by EnvList, which has the same functionalities as AgentList.

  • Model objects now have a property env that returns the first environment of the object.

  • Revision of Network. The argument map_to_nodes has been removed from Network.add_agents(). Instead, agents can be mapped to nodes by passing an AgentList to the agents argument of Model.add_network(). Direct forwarding of attribute calls to Network.graph has been removed to avoid confusion.

  • New and revised methods for Grid:

    • Agent.move_to() and Agent.move_by() can be used to move agents.

    • Grid.items() returns an iterator of position and agent tuples.

    • Grid.get_agents() returns agents in selected position or area.

    • Grid.position() returns the position coordinates for an agent.

    • Grid.positions() returns an iterator of position coordinates.

    • Grid.attribute() returns a nested list with values of agent attributes.

    • Grid.apply() returns nested list with return values of a custom function.

    • Grid.neighbors() has new arguments diagonal and distance.

  • gridplot() now takes a grid of values as an input and can convert them to rgba.

  • animate() now takes a model instance as an input instead of a class and parameters.

  • sample() and sample_saltelli() will now return integer values for parameters if parameter ranges are given as integers. For float values, a new argument digits can be passed to round parameter values.

  • The function interactive() has been removed, and is replaced by the new method Experiment.interactive().

  • sobol_sensitivity() has been changed to sensitivity_sobol().

0.0.5 (December 2020)

  • Experiment.run() now supports parallel processing.

  • New methods DataDict.arrange_variables() and DataDict.arrange_measures(), which generate a dataframe of recorded variables or measures and varied parameters.

  • Major revision of DataDict.arrange(), see new description in the documentation.

  • New features for AgentList: Arithmethic operators can now be used with AttrList.

0.0.4 (November 2020)

First documented release.