Demo models‎ > ‎Demo07‎ > ‎

4. The Person class

4.1 Entities

 
The Person class is an Entity class, as specified by the @Entity annotation:
 
@Entity
public class Person implements Comparable<Person>, EventListener, IDoubleSource {
    […]
}
  
This implies that the class is linked to a table in the database with the same name, and that all properties which are not annotated as @Transient are persisted in the database, when the simulation output is dumped. Entity classes must specify a PanelEntityKey (annotated as @Id), which is a three-dimensional object which identifies the agent id, the simulation time and the simulation run. These three keys uniquely identify each record in the database:
  
@Id
private PanelEntityKey id;
  
The ORM expects that the field names in the database are the same as the property names in the Java class, except when a different name is specified as in 
 
@Column(name="dur_in_couple")
private Integer durationInCouple;
  
Enumerations can be interpreted by the ORM both as a string and as ordinal values (0 for the first enum, 1 for the second, etc.), depending on how they are annotated:  
  
@Enumerated(EnumType.STRING)
private WorkState workState;
 
 

4.2 The IDoubleSource interface

 
The Person class implements the IDoubleSource interface. This interface provides a simple way of asking a class to return a specific value. (As such, it is also used by JAS-mine distribution plots, see Section 7.) Similarly to the EventListener interface, it requires to implement an Enum which lists all the variables that can be queried, and the getDoubleValue() method for returning their value (Box 11). It is used by the Regression classes as a way of decoupling the regression model specification from the code: as long as a variable is enumerated in the specific Enum called Regressors, it can be used (or removed) as a covariate in a regression model without the need to modify the code. (Regression classes also have a method to read directly the values of the variables from the agent class, without the need of implementing the IDoubleSource interface. However, this requires that all the variables used by a regression model are defined as (possibly transient) properties in the class. This is particularly tedious when the covariates refer to another agent - such as a potential partner, or the spouse - as is common in our case.)
 
 
 

public enum Regressors {

              

// For marriage regression, check with potential partner’s properties

        potentialPartnerAge,

        potentialPartnerAgeSq, 

        potentialPartnerAgeCub,

        potentialAgeDiff,

        potentialAgeDiffSq,

        potentialAgeDiffCub,

        inWorkAndPotentialPartnerInWork,

        notInWorkAndPotentialPartnerInWork,

 

[...]

 

// For in work regression

        age,

        ageSq,

        ageCub,

        isMarried,

        workIntercept;

}

        

 

public double getDoubleValue(Enum<?> variableID) {

              

        switch ((Regressors) variableID) {

                                     

        //For marriage regression

        case potentialPartnerAge:

                return getPotentialPartnerAge();

        case potentialPartnerAgeSq:

                return getPotentialPartnerAge() * getPotentialPartnerAge();

 

        [...]

                      

        //For work regression

        case age:

                return (double) age;

        case ageSq:

                return (double) age * age;

        case ageCub:

                return (double) age * age * age;

        case isMarried:

                return civilState.equals(CivilState.Married) ? 1.0 : 0.0;

        case workIntercept:

                return 1.0;    //Constant intercept, multiply regression coefficient by 1

                      

        default:    

                throw new IllegalArgumentException("Unsupported regressor " + variableID.name() + " in                                 Person#getDoubleValue");

        }

}

Box 11. Implementation of the IDoubleSource interface in Person.

4.3 Methods

 
The Person class implements the EventListener interface and is therefore able to be activated by the scheduler with the onEvent() method. The calls that a Person is able to respond to – enumerated in a specific Enum called Processes (Box 12) – are:
 
  • Ageing: age and marriage duration are increased; work status is set to retired if retirement age is reached.
  • Death: an age-, gender- and year-specific death probability is read from the MultiKeyCoefficientMaps pDeathM and pDeathF stored in the Parameters class; this probability is then compared with a uniformly distributed random number between 0 and 1 to determine the occurrence of the event:

            RegressionUtils.event(deathProbability);

If death occurs, the partner’s status is updated to widow and the person is removed from all the lists (that is, from his/her household and from the model).

  • Birth (applied to all females aged between 15 and 50 inclusive). An age- and year-specific probability of having a baby is read from the MultiKeyCoefficientMap pBirth stored in the Parameters class; then the occurrence of the event is determined in a similar fashion to the death() process. No multiple births such as twins can occur. Newborns are given a potential educational level that will be reached with certainty. Following the LIAM2 implementation, the person is assumed to be a student until completion of their studies (at age 16 for lower secondary education, 19 for upper secondary education, and 24 for tertiary education).
  • ToCouple (applied to all unmarried individuals aged between 18 and 90 inclusive). This method reads an age-, gender- and civil state-specific probability of forming a partnership from the MultiKeyCoefficientMap pMarriage and determines whether the Boolean flag toCouple is switched on (i.e. set to true), to be used by the marriageMatching() algorithm in the PersonsModel class.
  • GetALife (leave parental home): a new household is created if the individual is aged 24 or over, unmarried and still leaving in the parental household.
  • Divorce: after divorce is decided by the Model’s alignment method, partner links are broken, civil states are updated, females retain their household and males move to a newly created household.
  • InEducation: this method examines the person’s age and education level to determine whether an individual is still in education, or must exit education and enter the labour market as unemployed.
     

public enum Processes {

               Ageing,

               Death, 

               Birth,

               ToCouple,

               Divorce,

               GetALife,

               InEducation;

        }

Box 12. The Person.Processes Enum, defining the processes a Person undertakes when activated by the scheduler.
 
  
Other significant methods of the Person class include:
  • getMarriageScore(): computes the score of each male in the marriage pool, for a given female, based on a linear regression model specified by the MultiKeyCoefficientMap regMarriageFit; it is used by the marriageMatching() method in the PersonsModel class.
  • marry(): creates a link between the two partners and sets up a new household where they move to; it is used by the marriageMatching() method in the PersonsModel class.
  • computeDivorceProb(): computes the divorce probability, based on a logit regression model specified by the MultiKeyCoefficientMap regDivorce it is used by the divorceAlignment() method in the PersonsModel class.
  • computeWorkProb(): computes the employment probability, based on a logit regression model specified by the MultiKeyCoefficientMap regInWork; it is used by the inWorkAlignment() method in the PersonsModel class. 
 
 
Given that the regression coefficients have already been loaded from Excel files into the Parameters class, and the IDoubleSource interface method getDoubleValue() takes care of reading the values of the regressor variables, the simulation of outcomes or probabilities based on regression models is straightforward: 
 
marriageScore = Parameters.getRegMarriageFit().getScore(this, Person.Regressors.class);
 
divorceProb = Parameters.getRegDivorce().getProbability(this, Person.Regressors.class);
 
workProb = Parameters.getRegInWork().getProbability(this, Person.Regressors.class);
 
Again, if the specification of the model is changed by adding or removing covariates, or if new coefficient estimates become available, nothing has to be changed in the code, except for adding any new covariate to the Person.Regressors enum and providing a method for the new case in the getDoubleValue() method. 


Previous: 3. The PersonModel class             Next: 5. The Household class