Project 7: A population simulation

The goal of this project is to practice working on linked lists. The guts of this project is provided for you, but it depends on a linked list class which you must write.

1. Introduction

Suppose we are interested in dropping 300 19-year-olds onto an isolated island and observing the growth and other trends of the population over the course of 500 years, experimenting with various constraints on how the society they form works. Since time, cost, and ethics prevent us from running these experiments on real people, we will simulate this scenario in a computer program.

We will model the population and the people in the population with a collection of objects. For every "year" of the experiment, certain individuals of the population will give birth to new individuals, certain individuals will get married, and certain individuals will die. In this way the population will change over time (hopefully grow), and these things depend on rates of marriage, birth, and death. (We are assuming only married females give birth, and there is no divorce, though there is the possibility of remarriage if a spouse dies. Also, an individual must have lived a certain number of years before becoming eligible for marriage.)

Make a directory for this project and copy the given code.

cd cs235
mkdir proj7
cd proj7
cp /homes/tvandrun/Public/cs235/proj7/* .

2. Inspecting the given code.

Open Person.java. You will see what information we keep on a person. While a surname is a String, a given name is just a number serving as a unique identifier. A person has a birth year used to determine the person's age, and a person has a reference to a spouse. Finally, a person has a PersonList representing the collection of Person objects which are children of this person.

The PersonList class is where you will spend most of your work--only a skeleton is provided for you. For now we will observe what it should do by how the rest of the program uses it.

Open Population.java. This is the heart of the program with a very long main() method. First you will see some static variables representing parameters on population growth. This is what they mean:

Once you understand the code, you may choose to experiment with modifying these parameters. However, in my own experimentation these where the parameters that worked best. Modifying them to make the population grow faster resulted in the population growing so fast that soon the program slowed down significantly because of all the information to manage. Increasing the death rate to compensate caused the population to die out or grow only very slowly.

You'll also see a collection of surnames stored in an array.

Now inspect the main method. Skip the part at the beginning about namingPolicy; we will come back to that at the end. The entire population is modeled by a PersonList. We populate it initially with 300 people, 5 for each of the 60 available surnames. Since we are going to start the simulation at year 0, we give each of them a birth year of -19. Note that the PersonList class has a method add().

The big loop represents the years. First we handle births for that year. This requires getting a list of all married females. Notice that the PersonList class has a method for finding all such persons, and it returns them in another, smaller PersonList. Then for each iteration of the inner loop (for births), a random female is chosen from that list; take note that the PersonList class has a method for picking an element at random. Make sure you can follow all of the code in the "birth" section, except for the part about how a child's surname is chosen.

Next, the section on marriages. We use methods in PersonList to find all the females and males who are eligible for getting married this year. Follow that code carefully.

The section on premature deaths shows that the PersonList class must have a remove() method. More interesting, though, are the "old age" deaths. We want to give the list a birth year and have it remove all Persons with birth years earlier than that. However, we also want to update the spouses of all people that have died so that they now have null spouses and will appear as single. To do this, we need the PersonList to return all the items it removed---as a separate PersonList. Oh, but also, we want to iterate through that list, and so we would like to turn it into an array. Hence PersonList must also have a toArray() method.

3. Your task-- PersonList

Almost all of your work will be in this class. You will not need to modify Person or PersonNode, and you will make only trivial changes to Population (ie, uncommenting some code that has been commented out).

PersonList needs no explicit constructor--- head will be set to null by default and size to zero.

Write the following methods:

Warning: One of the most important concepts to grasp in all of this is the difference between a Person and a PersonNode. A Person object may exist in more than on list a the same time, but a PersonNode cannot (similarly, several PersonNodes could contain references to the same Person). Make sure this is clear before you try to write the methods listed above. Ask for help if it is not.

4. Running the program

When you think you have things written right and it all compiles, run the program:

java Population

You will notice the program slowing down near the end. Even with all the randomization, you will almost certainly end up with statistics at the end reading between 78% and 80% of adults being married, a population of between 12000 and 22000, and about 2.4 children for each person having children. Here's a typescript of the output of my solution at this point. If your numbers are different from these, there is probably something wrong.

5. Running an experiment

Uncomment the section at the end and run your program again. This will report on the size of the population for each surname and give a breakdown of the male/female split for each surname. Currently, children are given surnames in the "patriarchal" manner-- each child gets his or her father's surname. You'll notice that while most surnames that are still in use after 500 years have pretty even gender splits, a fair number of surnames will have died off.

Marilyn Vos Savant has proposed that male children should take their father's surname and female children should take their mother's (premarital) surname (see http://www.parade.com/articles/editions/2007/edition_11-25-2007/Ask_Marilyn). Apart from whatever other societal value that might have, for our interest it would have the effect of reducing the number of surnames that die out. Under the patriarchal system, a surname may die out not only if it fails to reproduce at all, but also if it merely reproduces only females.

A downside to Vos Savant's proposal is that it could lead to some surnames becoming lopsided in terms of gender balance. If a surname produced more females than males in one generation, it would be likely to produces an even greater percentage of females in the following generation. Eventually some surnames would be exclusively or almost exclusively male, others exclusively or almost exclusively female.

In our simulation, a child's surname is determined by an object that implements the NamingPolicy interface. Study that interface and the Patriacharl class that implements it. Then uncomment the code at the beginning of the main method that parses the args array and write two more classes that implement NamingPolicy:

The run the program several times experimenting with these policies. The -S flag with run Vos Savant's proposal, and -AS will run the third option. Does the third option keep the number of dead surnames low while also preserving gender balance?

6. Extra credit

Propose another interesting experiment and (after approval) implement it.

7. Turn in

Cat PersonList and the classes you wrote. Run the program with each policy.

DUE: Wednesday, Nov 11, at 5:00 PM.


Thomas VanDrunen
Last modified: Tue Nov 10 14:49:47 CST 2009