GithubHelp home page GithubHelp logo

zizroc / villager Goto Github PK

View Code? Open in Web Editor NEW
56.0 2.0 6.0 869 KB

villager is an extensible agent based modeling (ABM) framework for the R language. It supports agents, agent aggregations and their associated resources, as well as flexible data management.

License: Other

R 100.00%
simulation abm agent-based-modeling

villager's Introduction

villager

DOI R build status Codecov test coverage License: MIT

villager is a framework for creating and running agent based models in R. Its purpose is to provide an extensible framework where modeling can be done in native R.

Features

  • Extensible data output system (csv, excel sheets, sqlite)
  • Built in support for agents and resources
  • Easy to use time management

Installing

villager can be installed from CRAN by running the following,

install.packages("villager")

Takeaways

When reading though the Readme and vignettes, it's important to take note of a few concepts

  • Villages are the highest aggregate; they contain villages which in turn contain agents (agents)
  • Agents and resources can be subclassed to support additional properties
  • The data_writer class can be subclassed when writing to data sources other than csv
  • Models are functions that are added to villages; each village can exhibit different behavior

Using villager

villager is about modeling populations with (optional) associated resources. It supports a community level aggregation of agents, referred to as villages or an individual village. Agents, which are referred to as gender-neutral agents, are members of community level aggregations.

villager compliant models must conform to the function template below. The agent_mgr and resource_mgr are responsible for interacting with the individual agents and resources.

test_model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr) {
  ...
  ...
}

Creating & Managing Agents

Agents are created by instantiating the agent class. There are a number of agent properties that can be passed to the constructor.

test_model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr, village_mgr) {
  mother <- agent$new(first_name="Kirsten", last_name="Taylor", age=9125)
  father <- agent$new(first_name="Joshua", last_name="Thompson", age=7300)
  daughter <- agent$new(first_name="Mariylyyn", last_name="Thompson", age=10220)
}

To add agents to the simulation, use the provided agent_mgr object to call add_agent. Because the classes are R6, the object can be modified after being added to the manager and the changes will be persisted without needing to re-add the villager. For example, setting a daughter's mother and her father below. Note that the standard way is to modify the properties beforehand, although not strictly necessary.

test_model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr, village_mgr) {
  agent_mgr <- agent_manager$new()
  agent_mgr$add_agent(mother, father, daughter)
  daughter$mother_id <- mother$identifier
  daughter$father_id <- father$identifier
}

The agent manager can also be used to pair agents, representative of a relationship or social bond.

agent_mgr$agent_mgr$connect_agents(mother, father)

Creating & Managing Resources

Resources are similar to agents in that they're both R6 classes, are instantiated similarly, and are also managed by an object passed into the model. An example of creating resources and adding them to the simulation is given below.

test_model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr, village_mgr) {
  corn_resource <- resource$new(name="corn", quantity = 10)
  fish_resource <- resource$new(name="fish", quantity = 15)
  corn_resource$quantity=5
  
  resource_mgr <- resource_manager$new()
  resource_mgr$add_resource(corn_resource, fish_resource)
  fish_resource$quantity=5
}

State

Objects of type village, agent, and resourcehave particular states at a particular time. As the simulation progresses, the state of these change based on model logic. At the end of each time step, the state of each object is saved, giving a complete record of the system's evolution. The essence of any agent based model is changing the state at each time step. villager provides a mechanism for defining the initial state and for changing the state throughout the simulation.

Managing the Initial State

Creating the initial state is done by creating a function that resembles model functions from above. The manager classes are used to populate the village with an initial population of agents and resources.

initial_condition <- function(current_state, model_data, agent_mgr, resource_mgr) {
  # Create the initial villagers
  mother <- agent$new(first_name="Kirsten", last_name="Taylor", age=9125)
  father <- agent$new(first_name="Joshua", last_name="Thompson", age=7300)
  daughter <- agent$new(first_name="Mariylyyn", last_name="Thompson", age=10220)
  daughter$mother_id <- mother$identifier
  daughter$father_id <- father$identifier
  
  # Add the agents to the manager
  agent_mgr$connect_agents(mother, father)
  agent_mgr$add_agent(mother, father, daughter)
  
  # Create the resources
  corn_resource <- resource$new(name="corn", quantity = 10)
  fish_resource <- resource$new(name="fish", quantity = 15)
  
  # Add the resources to the manager
  resource_mgr$add_resource(corn_resource, fish_resource)
}

Creating Villages and Running Models

Models are tied to particular village instances. This binding is done when villages are created, shown below. Models can have names and must always be paired with an initial condition function and a model function.

small_village <- village$new("Test Model 1", initial_condition, test_model)

The simulator class is responsible for running simulations. It encapsulates all of the villages and controls the duration of the simulation. The simulator below runs for 100 time steps: roughly 13 years. The simulator can be paired with any number of villages, in the case of the simulator below, there's only a single village.

simulator <- simulation$new(100, list(small_village))
simulator$run_model()

Example: A small village with a single family

We can combine the examples above into a full simulation that...

  • Starts with an initial population of three villagers
  • Increases the age of each villager at the start of each day
  • Runs for 4745 days
  • Sets the villager profession after age 12
library(villager)
initial_condition <- function(current_state, model_data, agent_mgr, resource_mgr) {
  # Create the initial villagers
  mother <- agent$new(first_name="Kirsten", last_name="Taylor", age=9125)
  father <- agent$new(first_name="Joshua", last_name="Thompson", age=7300)
  daughter <- agent$new(first_name="Mariylyyn", last_name="Thompson", age=10220)
  daughter$mother_id <- mother$identifier
  daughter$father_id <- father$identifier
  
  # Add the agents to the manager
  agent_mgr$connect_agents(mother, father)
  agent_mgr$add_agent(mother, father, daughter)
  
  # Create the resources
  corn_resource <- resource$new(name="corn", quantity = 10)
  fish_resource <- resource$new(name="fish", quantity = 15)
  
  # Add the resources to the manager
  resource_mgr$add_resource(corn_resource, fish_resource)
}

test_model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr, village_mgr) {
print(paste("Step:", current_state$step))
  for (agent in agent_mgr$get_living_agents()) {
    agent$age <- agent$age+1
    if (agent$age >= 4383) {
      agent$profession <- "Farmer"
    }
  }
}

small_village <- village$new("Test Model", initial_condition, test_model)
simulator <- simulation$new(4745, list(small_village))
simulator$run_model()

Example: Creating new villagers

To demonstrate programatically creating villagers, consider the model below that has the following logic.

  • Starts with 10 villagers
  • Every even day, two new villagers are created
  • Every odd day, one villager dies
  initial_condition <- function(current_state, model_data, agent_mgr, resource_mgr) {
    for (i in 1:10) {
      name <- runif(1, 0.0, 100)
      new_agent <- agent$new(first_name <- name, last_name <- "Smith")
      agent_mgr$add_agent(new_agent)
    }
  }

  model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr, village_mgr) {
    current_day <- current_state$step
    if((current_day%%2) == 0) {
      # Then it's an even day
      # Create two new agents whose first names are random numbers
      for (i in 1:2) {
        name <- runif(1, 0.0, 100)
        new_agent <- agent$new(first_name <- name, last_name <- "Smith")
        agent_mgr$add_agent(new_agent)
      }
    } else {
      # It's an odd day
      living_agents <- agent_mgr$get_living_agents()
      # Kill the first one
      living_agents[[1]]$alive <- FALSE
    }
  }
  coastal_village <- village$new("Test village", initial_condition, model)
  simulator <- simulation$new(4, villages = list(coastal_village))
  simulator$run_model()

Advanced Usage

In the examples above, the default properties of agents and resources were used. It's possible that these won't cover all the needs for more diverse models. There are vignettes on extending the agent and resource classes to handle these situations.

Contributing

Code contributions are welcome as pull requests to the develop branch. Bugs, comments, and questions can be submitted as Github Issues.

villager's People

Contributors

gvaldana avatar ohmannyy avatar thomasthelen avatar zizroc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

villager's Issues

Create a Hex Sticker

All the cool people are doing it. See here.

We need a color scheme and a photo/library logo to do this.

Help Wanted: Code Review

We want to submit this to the folks at CRAN and get it approved. If there are any community members that are willing to devote some time (there's not a whole lot of code) to review the library code and submit feedback it would be appreciated! If you're interested in reviewing our code, reply to the issue and we'll get in touch :)

Look into List Copying

While writing the docs I'm running across some suspicious stuff in the resource_manager (that I've gotten to). Go back and check to see if there are better ways to add resources to the manager (I think we're copying them at the moment)

Fix Winik Ages

Ages are a little undefined. After discussion with @gvaldana we're now modeling ages in terms of days. Right now, ages are not incremented each day-this is something that villager should do so that modelers don't have to remember to do it.

Release 1.0

We should get 1.0 out so that we can start modeling basic villages. This issue is to make sure we're all on the same page as to what goes into it.

Requirements

Paraphrasing @zizroc in issue #10,

  • Functional trade between at least two villages
  • The ability to execute reasonable internal dynamics
  • The ability to couple environmental forcings*
  • The ability to support resources*
  • Sufficient documentation on how to use it
  • May be left to the user. For example, environmental forcings might be in the dynamics model, and the resources in a custom VillageState class.

Things completed

The ability to execute reasonable internal dynamics

This is currently possible to do with the library. See the vignettes folder for examples (need PR #15)

If there's anything missed or that needs to change leave a comment below!

Add Basic Trade

We need to let villages trade with eachother. The dynamics of trade isn't villager's responsibility, so we need to provide a way to let researchers describe them.

Work has been done on this front that lets a user create their own function that defines the trade dynamics.

This issue is to circle the wagons and take a look at what is currently possible with the base trade system and to beef it up if needed before moving on.

Add support for loading winiks from disk

We should add support to the winik_manager manager class for loading pre-defined winiks and populating the manager with them. The file that's being loaded will most likely be a CSV file where each row represents a new winik.

load()

The pseudo-code for this method looks like

initial_winik_file <- read.csv('winiks.csv)
for (line in initial_winik_file) {
   new_winik <- winik$new(name=line$name, father_id=line$father_id, .....)
   self$add(new_winik)

The file will look something like
winik

Make Everything Tidy

There's an issue for adding a linter, but converting the syntax and code style to something tidy will be a lot of work-hence this issue.

Requirements

  • Go through each file and convert the syntax to something that matches the tidy style guide (I think there are tools that do this automatically)
  • Search and destroy non-tidy things like for loops and make make them tidy
  • Go through the vignettes and make sure they're tidy

Notes

It would be best to do this while

  • a. There aren't any open pull requests
  • b. No one else is working on anything

Cram Additional Properties Into Subclassed VillageState Objects

Consider the following class that extends VillageState to include a new variable, aggression.

customState <- R6Class("demographicState",
                          inherit = VillageState,
                          public = list(aggression,
                            initialize = function(aggression=NULL) {
                                          # Let the base class initialize all of the other values
                                          super$initialize()
                                          self$aggression <- aggression
                                                              }
                                        )
                          )

We can create a new state object with

initial_condition <- customState$new()

But. We can't do something like (I'm trying to set the variable in the base class)

initial_condition <- customState$new(carryingCapacity=111)

Most languages have support for passing a variable number of arguments (for example pythons kwargs (actually exactly what I want to do)).

Goal: Use some sort of parameter pack/kwarg feature to pass values into the derived class's initialize method and feed them into the parent class.

https://www.geeksforgeeks.org/packing-and-unpacking-arguments-in-python/

Revert the Code Base

We should revert the code base to the the state where it had the population and resource managers.

Tidy up the DESCRIPTION File

We should include

  • The version of R that this depends on
  • A more accurate description (now that we know exactly what this is)
  • A better title
  • URL
  • Bug report link

Rename population_manager to winik_mgr

In an ideal world, the village class would have a member variable called winik_manager. Unfortunately, R makes you assign classes to variables. Since we named the winik manager winik_manager, it becomes ambiguous if we start creating variables called winik_manager that isn't a reference to the winik_manager class.

This is why the population_manager member variable in the village is called population_mgr instead of population_manager. When I initially wrote the winik_manager integration I didn't think of the possible _mgr ending-so I named it population_manager. There isn't a good synonym for resource, so I think the best option is to keep the first part of the class name, and just append _mgr to the end.

Add paper to new branch

JSOS requires the paper and bibliography exist in a separate branch.

Create a new branch and add the materials there.

Add support for user defined data writing

Because users can create their own winik & resource classes, we need to provide a way for them to write their data to disk. A new class, data_writer should be created. Users should override a write() method, which will get called at the end of each day.

Create README

The README should have at the minimum the appropriate badges, instructions for installing, and instructions for lightly using

Create VillageState from Tibble

Random thought: It's kind of a pain having to define custom R6 state objects. It would be great to be able to pass a data frame and tibble into the village's initial_state field. Internally we can convert it to our R6 object (for speed). I'll give an example below and we can see if it makes more sense to go this route.

Export Methods from Source Files

R's packaging system hooks up to the comments in the source code to generate a bunch of things. You MUST document classes and methods a particular way if you want the library to expose them to people (otherwise you run library(villager) but aren't able to use any of it).

Figure out and document the classes and methods so that R will export them.

Document the Architecture

Now that we have a little better idea what we want to support, we can start planning the overall architecture.

village class

This class represents the entire village, and exposes village features through the manager classes. The users interact with the manager classes in their models, and the village class.

manager classes

The manager classes are used to organize various components of the village and to cleanly expose an interface to village data. Each manager manages an aggregation of objects. For example, the trade manager should manage the trade objects. The winik manager should manage an aggregation of winik objects, etc.

resource, trade, and winik classes

These classes represent individual things: a single winik, a single resource, or a single trade.

In terms of a picture,

villager

Add Community Guidelines

JOSS requires there to be information about the following

Are there clear guidelines for third parties wishing to 1) Contribute to the software 2) Report issues or problems with the software 3) Seek support

We should add this information to the readme

Add support for variadic parameters in add_resource & add_winik

It's kind of messy having to call add_resource and add_winik over and over again. We should take advantage of R's ellipsis functionality to fix this.

For example,

  apples  <- resource$new("apple", 5)
  oranges <- resource$new("orange", 10)
  cabbage <- resource$new("cabbage", 20)

  resource_mgr$add_resource(apples)
  resource_mgr$add_resource(oranges)
  resource_mgr$add_resource(cabbage)

should be able to be written as

  apples  <- resource$new("apple", 5)
  oranges <- resource$new("orange", 10)
  cabbage <- resource$new("cabbage", 20)

  resource_mgr$add_resource(apples, oranges, cabbage)

Add Support for Grid Movement

We still want to support movement around on a 2x2 grid. This grid should be accessible to all agents. Each cell in the grid should be able to hold a reference to the agent that currently occupies the square. Each agent should have a member variable the holds the (x, y) location of where it is on the grid. It might be helpful to implement a random walk across the grid and place it in the agent class.

Increase Test Coverage of village_state and village

We're currently sitting at a coverage 87% which is pretty good; we can easily increase this by improving on the tests in village_state.R and village.R, which are currently in the 60% range for coverage.

Add support for resources

We'd like to support the notion of resources to villager. Right now, resource information is kept in the VillageState object but will need to be pulled out. See this issue to see how the resources will be integrated.

resource class

A new class should be created to represent each type of resource. The resource class can be thought of as a template for all resources. At a minimum, the resource object should have a name (fish, poultry, etc) and the amount that's currently present. The class should also be an R6 class so that we can modify its state.

When the resource class is finished, new resource objects should be created as

fish <- resource$new(name='fish', quantity=10)
maize <- resource$new(name='maize', quantity=0)

resource_manager class

The resources should be accessed through a new class, called resource_manger. The village class should have an instance of this object, and should also expose it to user defined models (see how winik_manager is used in the propagate function).

This class should have at least two methods: add(resource) and 'get(string resource_name)`.

fish <- resource$new(name='fish', quantity=10)
maize <- resource$new(name='maize', quantity=0)
resource_store <- resource_manager$new()
resource_store$add(fish)
resource_store$add(maize)
maize <- resource_store$get("maize")

Saving & Loading

Eventually we'll want to be able to save the resources and re-load them. This will give similar functionality with the winik manager which will be able to save and load winiks. Like loading winiks, this will allow us to load

The database table describing the resources will look something like the following
resource-table

The resource_manager should have a function, load(), for loading a csv of resources, creating a new resource object for each one, and then adding each new resource object to the manager.

modifying resources in custom models

Users should be able to add and modify resources in their custom models. I added a unit test below (untested so there may be syntax errors) to show what it would look like on the user's end to modify the resource.

test_that("resources can be modified in a model", {
  # Create a model that adds 1 unit of poultry every day, starting with 0
  resource_model <- function(currentState, previousState, modelData, population_manager) {

   # Set the initial conditions at year==1
   if (currentState$year ==1) {
        poultry<- resource$new(name='poultry', quantity=0)
        self$resource_manager$add(poultry)
    }
   else {
         polutry_stock <- resource_manager$get('poultry')
         poultry_stock$quantity <- poultry_stock$quantity + 1
   }
  }

  # Create a default village
  new_state <- VillageState$new()
  plains_village  <- BaseVillage$new(initialState=new_state, models=resource_model)
  # Run for 5 days
  days_to_run <- 5
  new_siumulator <- Simulation$new(length = days_to_run, villages = list(plains_village))
  new_siumulator$run_model()
  testthat::expect_equal(new_siumulator$villages[[1]]$resource_manager$get('poultry'), 5)
})

Unit tests

Two new files, test-winik.R and test-winik_manager.R should be made in the unit test directory. The test_winik tests should test that the constructor works as expected. The test-winik_manager tests should test that

  1. The constructor works
  2. The add method works as expected
  3. The get method works as expected
  4. Modifying a resource's quantity persists

An integrated test should be added (will most likely look like the test I pasted above) to test that

  1. Users can add any number of resources at year==1
  2. Users can modify the quantity of said resources and the quantity persists over time steps

Add a Linter

I've completely butchered the styling which is probably an artifact of working with a different R package that uses a different styling.

I think we agreed on the tidyverse style?

Add a linter to the package so that we're notified when we deviate.

Fix winik states

When a winik's state is a written, it's written as a tibble. See here for reference. It turns out, some of the values may be null, which tibble won't handle and R won't throw an error (even though the tibble is never created).

Figure out of to fix this.

Hook up With Travis CI

We should be doing automated builds when we push new code and make pull requests. This lets us know if the code coverage decreased (not enough unit tests) or if something broke the package.

We should be automating the testing on both UNIX and macOS-Travis doesn't yet support Windows with R

vignettes or ...?

figure out whether this can go in documentation or whether we should throw in some examples

Add Support for

We need an easy way to tell how long its been since a winik had a child. Add a method that returns the age of the youngest child for a winik, which is the time since last birth

Add Support for Days and Months

Background

In the Sept 17th call, we decided that we want to add support for representing time using the Mayan calendar system. The main goal of this is to tie events to particular dates.

Use Cases:

I want to be able to tell, based on a year and month what season it is and what events happen that month.

I want to be able to convert from the Mayan calendar system to the Gregorian system

Other Questions

Which calendar system do we want to support? It looks the the two predominant ones are the 260 day calendar and the 365 day calendar? It's of course possible to support both, but would take more time.

Other Notes

If we're adding support for the month and year-we're going to have to inevitably do it for days too (not a big problem).

Right now we're using the word 'year' as a proxy for the time step. What the year actually represents is dictated by the dynamics defined in the model (my opinion). It sounds like we want to iterate the timestep on the daily resolution, which is fine. I want to make sure we don't lose the ability to simulate on the daily or yearly level either.

To get around this, I'm thinking that we let the user decide the timescale by the way they specify dates. We also don't want to restrict the usage to just the mayan calendar, so we need to define what a mayan date looks like. For example, ISO_8601 clearly defines the format for a date in the Gregorian calendar.

Take the following Gregorian date, 1900-01-01, January first of 1900. Because the year, month, and day were specified-the model runs at the daily resolution. If someone enters the start date as 1900-01, the simulation would run on the monthly level. If someone enters 1900, then it's run on a yearly timescale.

Because the Mayan calendar system is mappable to the Gregorian calendar, I propose we use the Gregorian calendar, within the villager library.

Because dates are important in the models, most of the mayan date time checking will be done outside of villager. For example, if a trade is to be done on each day that is Imix-that logic goes in the researcher's trade function.

Solution

Because the Mayan date time features belong outside of villager, I propose we make a new library (or use an existing, see below) for converting Mayan date times to ISO 8601.

Features

  1. Convert from ISO-8601 to ______ (preferred Mayan calendar)
  2. Given a Mayan calendar date, tell me what the season is
  3. Given a Mayan calendar date, tell me what events are happening on that date (so we can decide whether to trade or not)
  4. Given a Mayan date, give me the pictorial representation (Bonus points)

To Do

  1. Figure out a clever name
  2. Create a repository using the clever name
  3. devtools::create("clever-name")
  4. Create functions for doing features 1-3

Usage

An example of what this would look like if a trade was allowed to happen every 20th day (when events were held)

library(clever-name)

trade <- function(currentState) {

mayan_date <- as.tzolkin(currentState$year)

if (tzolkin.name(mayan_date)) == 'Ajaw') {
# Then do some trade
}


}

Create Unit Tests

We should have unit tests for all of the classes and will need them if we plan on releasing to the public.

Rename BaseVillage Class to village

The BaseVillage has that names for historical reasons (There used to be subclasses). We really only need a single village class, so we might as well call it villager. As per tidy naming, its lower cased.

  1. Rename BaseVillage to village
  2. Change the file name to village
  3. Go through all of the documentation and other code, making sure it's all accurate

Check minimum dependencies

We might have a few dependencies defined that we no longer need. Go through an make sure that the minimum ones are defined.

[Trade] Trade Contracts

Villages should be able to write trade agreements that are executed, based on some condition.

This will most likely work by.....

When village A goes to trade with village B, village A will propose a new state for village B. Village B will have to either accept or reject the trade. If B accepts the new state, then the village B state is updated. I'm not sure how it will look for village A, because it needs to know if village B accepted the trade or not.

Worst case is that we create a new Broker class that keeps track of all of the proposed trades.

Create an Agent Class

After the 03/14/21 discussion we want to add some sort of 'Agent' class. It'll probably be more defined over time but off the top of my head it should probably (up for discussion),

have a field for at least,

  1. An identifier
  2. A list of other agents that it may contain
  3. Agent data (maybe we'll make this hold an R6 class in the future)

have methods for

  1. adding other agents to its list of agents.
  2. Adding a list of agents to the agents
  3. propagating through time (it should be an empty function)

There should also be some unit tests testing the constructor and and the relevant functions.

Figure out a release schedule

We should be versioning this package so that people can go back and use old versions from old papers. We should of course go with the usual 1.0, 2.0, major.minor.

What do we want to include in what we call 1.0? Everything except trade? Include trade and say that trade+custom dynamics is 1.0? Up for discussion.

Pick a License

Right now the package check will fail with

> checking DESCRIPTION meta-information ... WARNING
  Non-standard license specification:
    `use_mit_license()`, `use_gpl3_license()` or friends to pick a
    license
  Standardizable: FALSE

which means we can't publish it and other legally can't use the code.

This issue is to track the progress of selecting a license, which should be done 9/11/20

I would hope that the R command to generate the license actually generates the file too. In addition, we'll want to put a license badge on the README.

Population growth for trading villages

Population growth should be logistic with growth from (1) intrinsic (births and deaths) and (2) due to population "trades" (viz. raiding). Should look something like this, for 2 trading villages.

growth_village_a <- function(currentState, previousState, modelData){
  
  #the growth rate should be conditional, not constant like it is defined below
  growth_rate <- initialVillageState$birthRate - initialVillageState$deathRate
  
  #carrying capacity might be conditional too, but constant is ok for now
  carrying_capacity <- initialVillageState$carryingCapacity
  
  currentState$population = previousState$population + growth_rate*previousState$population*(1 - previousState$popuation/carrying_capacity)
  
}

#same here
growth_village_b <- function(currentState, previousState, modelData){
  
  #the growth rate should be conditional, not constant like it is defined below
  growth_rate <- initialVillageState$birthRate - initialVillageState$deathRate
  
  #carrying capacity might be conditional too, but constant is ok for now
  carrying_capacity <- initialVillageState$carryingCapacity
  
  currentState$population = previousState$population + growth_rate*previousState$population*(1 - previousState$popuation/carrying_capacity)
  
}

Write the code documentation

There's a significant amount of documentation needed around methods, examples of them, and general bookkeeping. This issue is for writing it up. Related to #26 and being completed in the code_docs branch

Decide on Developer Habits

I'm guilty of being a cowboy coder; working on a ranch long enough might do that to you ;)

I'm sure @zizroc is at this point, tired of my "Oh I literally just pushed 2 minutes ago rebase", "Oh yeah yesterday I made that change, you'll have to pull", "Bro it's going to be a j4ck3d merge when you get the latest changes", etc comments. Continuing on like this would be madness, and it would bee better to keep everyone in the loop before new code is added. This will slow things down which at this point should be okay. We have the base state machine and now we're adding extensions to it (like trade).

I hate too much structure and don't want to opt for a full development process because it makes software a dead black and white dismal thing (personal opinion).

  1. All code is added through a pull request and approved by 2 people
    This means that most of us will have seen the new changes and know that we need to update our branches. It also forces us to keep up with the codebase. Over time we will have seen and judged just about every line that goes in.

  2. Pull requests are linked to issues
    When there's a bug, it's good to get context as to where it came from (so that the fix doesn't break anything). It's also nice just for record keeping (ie why did we pick license X?). I'm pretty relaxed on this one, but think that it might be a good idea.

What do all think?

Fix the Linter Warnings

The linter errors in the Travis logs need to be fixed. To see them, visit travis, select a build, and then view the Rscript -e 'lintr::lint_package()' logs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.