The Wolfram Emerging Leaders Program: Boot Camp is a year-long program for talented high school students. Students spend a semester learning Wolfram Language, and then work in a small group over the second semester to do either a research-based project or a product development–based project under the guidance of an expert mentor. Projects are centered around a topic at the intersection of the group’s interests.
◼
  • Yash Juneja
  • ◼
  • Om Kalyani
  • ◼
  • Shreraj Sainani
  • Abstract

    In this work, we present a custom bioenergetics-informed ecological Agent-Based Modeling (ABM) toolbox for colonies of artificial organisms in the
    Wolfram Language. We investigated energy and population dynamics with connections to real-world biology using this toolbox. Unlike previous
    Agent-Based Modeling projects done in the Wolfram Language, our interactive toolbox provides the user with the ability to change and visualize the effects
    of the parameters used by the artificial colonies such as resolution of simulation time-discretization, sensing and interaction abilities of organisms,
    metabolic rates, lifespans, exploration/foraging behaviors, reproductive frequencies, and bioenergetics like digestion and reproduction energies. Our tests
    show that ecological models produced by the toolbox mimic population dynamics on a macro-level as seen in real-world ecology through experimentation
    on metabolic rates, primary production rates, caloric densities and reproductive frequencies with a logistic analysis of population growth and collection of
    other demographic data.

    Introduction

    We developed an agent-based modeling toolbox to study how simple bioenergetic rules shape population-level dynamics. In the model, individual agents move through an environment bounded by a square, sense food, interact with other agents, consume energy, reproduce, age, and die. Each agent follows relatively simple rules, and the population as a whole can show certain emergent behaviors that will be discussed in this study, such as logistic growth, carrying capacity, variation in reproduction timing, and differences in mortality. The toolbox’s simulation logic incorporates movement, organisms dynamically sensing their environment and adjusting foraging and mating decisions, energy consumption, reproduction, and aging, as well as a visualization that maps each timestep to show how agents undergo all of these behaviors, which are informed through bioenergetics. Bioenergetics is the study of how organisms acquire, transform, store, and expend energy, and how those energy flows determine biological outcomes like growth, reproduction, movement, and survival
    [RN1]
    . With this ‘toolbox,’ we test how environmental and biological parameters affect population outcomes. Specifically, we vary factors such as food availability, metabolism, reproduction energy cost, and reproduction age, then record their effects on population size, carrying capacity, growth rate, first reproduction age, and lifespan. Since our model has limited space that introduces competition between agents (if two agents attempt to eat the same food it is determined randomly which eats it) and a constrained amount of food that is spawned (simulating primary production in an ecosystem), the environment has a limited potential for growth, and the populations of colonies were accordingly found to naturally trend towards logistic growth. Logistic growth is governed by the following differential equation, which embeds the constrained nature of the population growth into its structure with the
    1-
    P
    K
    factor
    [NG1]
    :
    dP
    dt
    =rP1-
    P
    K
    (1)
    Separating and integrating this differential equation gives the form that we use among other curves to fit to our population data among other data for analysis
    P(t)=
    K
    1+
    -rt
    Ae
    (2)
    Where K represents carrying capacity, r represents intrinsic growth rate, and A represents the relationship between the initial population and carrying capacity. These variables allow us to compare how different parameter values affect population-level behavior as a whole.​ Overall, through these experiments, we show how simple rules can influence a population’s dynamics and characteristics, and how our Agent-Based Modeling toolbox can be used as a flexible foundation for studying further ecological systems and emergent population-level and agent-level behaviors not only because it exhibits such behavior like logistic growth, but also because of its flexibility from the infinite possibilities its large number of customizable parameters provides.

    High-Level Model Development

    We designed our Agent-Based model from the ground up to be customizable for the user, making it easy to run experiments and test hypotheses. The simulation is complete with visuals and animations, showing what’s going on behind the raw data. All behavior, except for random movement when needed, is deterministic and always based on the starting parameters. It is important to note that agents do not “feel” or are not provided “rewards” by the simulation. Rather, natural selection drives some agents to do better than others, causing other agents to die out, showing how certain parameters support life better or worse. Agents are organisms with age and energy, must consume resources to survive, move, reproduce, and optionally invest energy in offspring. When deciding on what action an agent takes every time step, we took inspiration from a British Ecological Society paper outlining the general order of importance:
    “If there is sufficient energy intake, an animal allocates the energy obtained in the order: maintenance, growth, reproduction, energy storage, until its energy stores reach an optimal level. If there is a shortfall, the priorities for maintenance and growth/reproduction remain the same until reserves fall to a critical threshold below which all are allocated to maintenance.” - [RS1]
    In our model, agents unavoidably lose energy every time step through “metabolism.” When deciding to take an action, in the agentActions function, we first look at if the agent meets all the criteria to reproduce. This includes having enough energy, having another non-related agent in the sensing radius, not being on a reproduction cooldown, and having existed for long enough. Agents need a minimum amount of energy before looking to reproduce because growth/sustenance is of a higher priority than reproduction
    [RS1]
    . If there is no suitable mate, the agent then looks for food in proximity. If it is close enough, it eats it. If not, the agent moves towards the food. And finally, if the agent doesn’t see anything in its radius, it picks a random exploration direction and walks. The agent has a random chance to change directions every time step when exploring, so it is able to more effectively explore a single direction before looking elsewhere. If an agent tries to leave the bounds, its position is clipped to the bounds, and if it is half a step away from the bounds, the direction it is moving in changes. The environment supplies food containing energy every timestep to simulate primary production (usually plants producing organic matter from sunlight) in the ecosystem. Because of this, the organisms we simulate are primary consumers.

    Model Parameters

    These are model parameters stored as an association that set the rules for a simulation, and a user may freely tweak them to model certain environmental scenarios or use these as independent variables to run empirical experiments. Most functions of the model take in this parameters association to understand how they should work and to what extent their functions should affect model/agent state. Comments following each parameter outlines its purpose. Parameters, and thus the model, is defined in nondimensionalized arbitrary units: arbitrary distance units denoted (D), arbitrary time units denoted (T), and arbitrary energy units denoted (E) throughout.
    In[]:=
    parameters = <|​​ "proximityRadius" -> 0.5, (*How close two things (agent/food, agent/agent) need to be to interact (eat, reproduce, etc.)*)​​ "sensingDistance" -> 4, (*How far agents can sense items*)​​ "metabolism" -> 0.05,​​ "dt" -> 0.1, (*timestep*)​​ ​​ (* Food/environment *)​​ "foodEnergy" -> 5.0,​​ "foodSpawnCooldown" -> 1,​​ "nFoodSpawn" -> 5,​​ "nStartingFood" -> 4,​​ ​​ (* Initial population and movement *)​​ "nStartingAgents" -> 4,​​ "squareBounds" -> {0, 20},​​ "startingEnergy" -> 10,​​ "stepLength" -> 0.4,​​ "dirChangeProb" -> 0.025,​​ "lifespan" -> 30,​​ "maxEnergy" -> 10,​​ ​​ (* Visualization *)​​ "imageSize" -> 500,​​ "agentSize" -> 0.01,​​ "foodSize" -> 0.0075,​​ ​​ (* Reproduction *)​​ "reproductionRadius" -> 1.0,​​ "minReproductionEnergy" -> 5.0,​​ "minReproductionAge" -> 4.0,​​ "reproductionEnergyCost" -> 2.0,​​ "reproductionCooldown" -> 2,​​ ​​ (* Variables for numerical stability *)​​ "epsilon" -> 0.001,​​ "rnd" -> N@10^-3​​|>;

    Core Model

    Data Structures

    Before the rest of the toolbox was built, the core aspects of the model like agents that moved and consumed food were built first. The food in a model at any time is represented by a list of positions of pieces of food. For the data structure of the model as a whole, see Model Initialization.
    createAgent[]
    is used to initialize agent associations, and their states can be accessed through keys. Each agent attribute is commented with a description of its nature
    In[]:=
    createAgent[pos_, energy_, age_, id_, currentDirection_, parents_:{-1, -1}, reproductionCooldown_] := <|​​ "pos" -> pos, (*The current position of an agent in the environment, length 2 array*)​​ "energy" -> energy, (*The current energy of an agent*)​​ "age" -> age, (*The current age of an agent*)​​ "id" -> id, (*A unique identifer given to each agent created throughout the history of the simulation instance*)​​ "currentDirection" -> currentDirection, (*The current direction the agent is exploring in or seeking food/mates in; value from [0, 2pi)*)​​ "parents" -> parents, (*The ids of the agent's parents in a length 2 array. If the agent is one of the primordial starting agents, {-1, -1} is given to this value.​​ used to determine familial relations for the purpose of incest prevention--a parent will naturally not reproduce with their child throughout almost all species*)​​ "reproductionCooldown" -> reproductionCooldown​​|>

    Core Functions

    These functions are the basic operations needed for core model functionality.
    The function first compiles the food positions and indexes, and then isolates the ones that are within sensing distance of the agent. If no pieces of food make it into that isolation, then there are none within sensing distance and {-1, -1, -1} is returned. Else, the closest food’s {distance, index in the food list, position in the environment} is returned.

    Reproduction

    Helper Functions

    Main Reproduction Function

    Agent Rules and Behavior

    Helper Functions

    Main Agent Decision Logic

    1
    .
    Does an agent meet all the criteria for reproduction with a nearby agent? i.e. has it satisfied its needs of maintenance and survival?
    1
    .
    3
    .
    If no, then continue
    2
    .
    Is the agent near a piece of food and is it close enough to eat it?
    2
    .
    2
    .
    If no, then continue
    3
    .
    Does the agent see (sense) any food?
    4
    .
    Are none of the above true? i.e. does the agent not see any food and does it not meet any of the criteria for reproduction?

    Model Initialization

    Model Propagation

    Producing the Simulation Object

    Analysis

    Calling the function on our simulation, we can see the curve fitted...
    The distribution of first reproduction ages shows that most agents reproduce almost immediately after reaching the minimum reproduction age, which, in this experiment, was set to 4. Moreover, this suggests that the environment is rich in resources and thus conducive to the population’s growth, as agents can have sufficient energy and food to reproduce immediately and find mates. Additionally, the median first reproduction age of 7.40 furthers this pattern, indicating that at least half of the agents reproduce early in their lifespans. Also, the distribution is right-skewed, which explains the disparity between the mean and median age at first reproduction (9.70 and 7.40, respectively). Most agents reproduce before 10 T of age, which is 6 T after they reach reproductive maturity. There are however some, that do not until later ages, and this likely occurs in high-competition scenarios near carrying capacity. A quarter of the agents reproduced as soon as possible before reaching an age of 5 T.

    Visualization

    Two scaling functions are used to convert between D units and pixels for the image based on the parameters of the model
    For our visualization, we created a function called displayGrid which styles the text, energy bars, etc. and formats the agents with the function drawAgentGraphic. Initially, we combined all these aspects of our code into displayGrid itself by using the Module function inside of Table, but we found that using a separate function, such as drawAgentGraphic, to handle other formatting allows us to significantly increase efficiency. First, we gather the following information
    To simulate how agents interact with one another in an environment, we created a square visualization window bounded by the parameter squareBounds to render agents, food/resources, energy levels, ages, and other characteristics for each timestep. The function first extracts all agent information from the main association.
    Additionally, an important variable is span, which we use to scale the visualization with the size of the modeled world, so the display remains consistent even when the environment changes.
    Since the bounds of the environment can change, we scaled the graphics to the bound of the world. Specifically, if the environment is small, agents and food appear larger, whereas if the environment is large, the agents appear smaller.
    To keep the visualization clean and prevent the grid from looking ‘crowded’ as the population increases, we used the current population size to control how much detail to display. As a result, energy bars are only shown when there are less than 6 agents
    The agents’ properties, such as age and energy level, are represented by color gradients. Specifically, age is shown by a green (young agent) to red (old agent) gradient. It is important to note that the agents’ ages are relative to their total lifespan. This allows us to display the age visually, without crowding the grid with other legends.
    We also switch the text color between black and white, depending on each agent’s age, to keep the age readable against different gradient colors.
    The energy of each agent is represented by a red-to-green bar, in which red represents low energy, while green represents a high energy. These energy levels are relative to the max energy defined in the associations.
    Initially, we found it difficult to avoid overlap between text/agent information when agents are close together in the grid. So, to fix this, we wrote a helper rule to check agent positions and test multiple possible locations for the energy bar. Now, the function takes into account the positions above, below, left, and right, clips them to stay inside the grid, and, by using a scoring method, finds what position maximizes distance from nearby agents. Overall, this makes the visualization more readable.
    Within drawAgentGraphic, we extract each agent’s information and create local variables for the agent’s position, age, energy, energy fraction, display colors, and energy-bar placement.
    Then, we convert each agent’s energy into a fraction between 0 to 1, which controls both the length and the color of the energy bar. The variable percent creates the number that is displayed in the energy bar.
    Moreover, the following lines determine the agent’s circle color based on age and choose a legible text color for the age label.
    One of the most difficult yet important aspects for our project was choosing the correct energy bar placement. We created a function that tests possible positions around the agent and chooses the location that is farthest from other agents while staying inside the simulation bounds.
    Additionally, we used small white disks to represent food in our simulations.
    For clarity, we added a legend to the top left of the grid to explain labels for the agents, energy bars, and food. It also shows the current time, remaining food count, and number of agents in the model. To ensure that the legend stays consistent for varying bounds, we anchored it relative to squareBounds. Additionally,
    This visualization code is combined in the closed cell below--if this notebook is being edited, it can be edited once the cell is opened.

    Visualizing the Simulation

    Experimentation

    To demonstrate the capabilities of our model and connect its results to those of real world biology, experiments are presented here. For clarity, just the results and not the code for these experiments is here. The latter may however be found in the project’s Github. Our importing and exporting system was used to save these simulations after they were run so we could perform analysis on them.

    Dependent Variable 1 - Carrying Capacity K

    2000 timesteps were used for these simulations, and unless a variable is the independent variable in each of these experiments, the parameters of these simulation are as they are in this computational essay.
    Metabolism (E/T) vs Carrying Capacity​
    This graph shows an inverse relationship between metabolism and carrying capacity. As the metabolic energy cost per timestep increases, the carrying capacity decreases drastically, which indicates that agents consume energy faster than they can replenish it through energy resources like food. This faster than linear decrease opposed to the food energy linear increases could possibly be explained by the fact that having a higher metabolism causes compounding decreases in efficiency since metabolism occurs every timestep.The strong fit (R^2=0.998), which shows that metabolism is a limiting factor on long-term population stability. Moreover, at low metabolism values, agents can survive and reproduce more efficiently, whereas at high metabolism values, the environment can only sustain a smaller population before the low amounts of energy cause populations to decline.
    ​
    ​Food Spawned per Timestep (1/T) vs Carrying Capacity
    ​The second graph shows a positive linear relationship between food availability and carrying capacity. As the number of food particles spawned per timestep increases, the carrying capacity increases proportionally, which shows that the amount of food directly controls the maximum sustainable population size within the simulation. This is reinforced by the reliable fitness of the model (R^2=0.999), which suggests that under the current model assumptions, resource availability is one of the most important variables that controls population growth. Moreover, these results align well with ecological expectations, since an increase in resources naturally allows more organisms to maintain the necessary energy levels for survival and reproduction [BT1].
    Food Energy (E) vs. Carrying Capacity​
    This graph shows a strong positive linear relationship between food energy and carrying capacity (R^2 = 0.988). Moreover, as the amount of energy supplied by each piece of food increases, populations can grow to large numbers and sustain themselves in the long-term because agents can replenish energy more efficiently each time they eat. Overall, this suggests that, regarding a population’s growth, the amount of food available may not necessarily play a larger role than the quality of the food. In fact, this shows that environments with more nutrient-dense pieces of food can support growing populations even when the amount of food remains constant or is lowered.
    ​
    ​Reproduction Cooldown (T) vs. Carrying Capacity​
    This graph shows an overall negative relationship between reproduction cooldown and the carrying capacity of a population. As the cooldown increases, the carrying capacity decreases, likely because agents are limited to reproducing less frequently. However, the relationship is less smooth than in previous graphs; indeed, there are fluctuations present on the interval [2.0, 2.5], showing that reproduction cooldown has a more indirect effect on carrying capacity as opposed to other factors like food energy, reproduction cost, or metabolism. This is likely due to how reproduction timing aligns with the random movement of agents and food availability, which makes the impact of cooldown periods more sensitive to arbitrary events in the simulation.
    Reproduction Energy Cost (E) vs. Carrying Capacity​
    This graph shows an overall negative relationship between reproduction cooldown and the carrying capacity of a population. As the cooldown increases, the carrying capacity decreases, likely because agents are limited to reproducing less frequently. However, the relationship is less smooth than in previous graphs; indeed, there are fluctuations present on the interval [2.0, 2.5], showing that reproduction cooldown has a more indirect effect on carrying capacity as opposed to other factors like food energy, reproduction cost, or metabolism. This is likely due to how reproduction timing aligns with the random movement of agents and food availability, which makes the impact of cooldown periods more sensitive to arbitrary events in the simulation.

    Dependent Variable 2 - Intrinsic Growth Rate r

    2000 timesteps were used for these simulations, and unless a variable is the independent variable in each of these experiments, the parameters of these simulation are as they are in this computational essay.
    Unlike the carrying capacity curves, the growth rate curves all show several fluctuations rather than monotonic relationships. Moreover, the growth rate oscillates for the parameters like metabolism, food spawn rate, food energy, reproduction energy cost, and reproduction cooldown. This shows that in the simulation, the growth rate is extremely sensitive to events like random movement, locations of food spawning, or reproduction timing, likely more so then environmental parameters. Additionally, growth rate inherently measures the short-term changes in the population, making its curves seem much more unstable than carrying capacity, which measures the long-term equilibrium of a population. This further adds to the likelihood that small differences in how agents interact with the environments can impact the growth rate largely, noted that the environmental parameters that were used as independent variables in these experiments didn’t seem to have much of an effect. For example, the ability of agents to find each other early in the simulation history when the population is sparse significantly impacts the success of the future population and how quickly it grows.

    Dependent Variable 3 - Life Expectancy

    As the cost of reproduction energy increased, the average age at death for agents actually increased for reproducers. Agents were classified as reproducers if they had reproduced at least once in their instance of the simulation, and were otherwise classified as non-reproducers. In most ecosystems, as reproduction gets more expensive, we would expect to see average life spans to decrease, coming from the classic life-history trade-off prediction [GW1]. However, because our simulation doesn’t have predators, it’s a better model for isolated environments, like oceanic islands before human contact [IS1]. In these environments, organisms have low mortality factors and are able to live long lives with low reproduction rates due to a higher cost of reproduction. Interestingly, our ABM, starting with simple rules grounded in reality, happened to mimic real ecosystems for these variables too.

    Conclusion

    Future Direction

    Acknowledgements

    References

    [RS1] Richard M. Sibly et al. (2013), “Representing the acquisition and use of energy by individuals in agent-based models of animal. https://doi.org/10.1111/2041-210X.12002
    [GW1] George C. Williams (1966), “Natural Selection, the Costs of Reproduction, and a Refinement of Lack’s Principle”, The American Naturalist 100(916): 687–690. https://doi.org/10.1086/282461
    [NG1] Nicholas J. Gotelli (2008), A Primer of Ecology, 4th edition, Sinauer Associates, Sunderland, MA.
    [BT1] Michael Begon, Colin R. Townsend, and John L. Harper (2006), Ecology: From Individuals to Ecosystems, 4th edition, Blackwell Publishing, Oxford.
    [BR1] James H. Brown, James F. Gillooly, Andrew P. Allen, Van M. Savage, and Geoffrey B. West (2004), “Toward a Metabolic Theory of Ecology”, Ecology 85(7): 1771–1789. https://doi.org/10.1890/03-9000
    [RN1] Roger M. Nisbet, Erik B. Muller, Konstadia Lika, and S. A. L. M. Kooijman (2000), “From molecules to ecosystems through dynamic energy budget models”, Journal of Animal Ecology 69(6): 913–926. https://doi.org/10.1111/j.1365-2656.2000.00448.
    [IS1] Gregory H. Adler and Richard Levins (1994), “The Island Syndrome in Rodent Populations”, The Quarterly Review of Biology 69(4): 473–490.

    CITE THIS NOTEBOOK

    Investigating ecological energy and colony population dynamics with agent-based modeling​
    by Yash Juneja, Om Kalyani and Shreraj Sainani​
    Wolfram Community, STAFF PICKS, August 31, 2026
    ​https://community.wolfram.com/groups/-/m/t/3790026