Skip to content

Commit

Permalink
Update partnership alignment process
Browse files Browse the repository at this point in the history
  • Loading branch information
pbronka committed Nov 15, 2023
1 parent 7fdcaf5 commit 874c257
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 48 deletions.
Binary file modified input/policy parameters.xlsx
Binary file not shown.
13 changes: 12 additions & 1 deletion src/main/java/simpaths/data/Parameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ else if(numberOfChildren <= 5) {
//Uprating factor
private static MultiKeyCoefficientMap upratingIndexMapGDP, upratingIndexMapInflation, socialCareProvisionTimeAdjustment,
partnershipTimeAdjustment,upratingIndexMapWageGrowth, priceMapSavingReturns, priceMapDebtCostLow, priceMapDebtCostHigh,
wageRateFormalSocialCare, socialCarePolicy;
wageRateFormalSocialCare, socialCarePolicy, partneredShare;
public static MultiKeyMap upratingFactorsMap = new MultiKeyMap<>();

//Education level projections
Expand Down Expand Up @@ -2408,6 +2408,8 @@ public static void loadTimeSeriesFactorMaps(Country country) {

// load year-specific fiscal policy parameters
socialCarePolicy = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "social care", 1, 8);
partneredShare = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "partnership", 1, 1);

}

public static void loadTimeSeriesFactorForTaxDonor(Country country) {
Expand Down Expand Up @@ -2667,6 +2669,15 @@ public static void setProjectWealth(boolean val) {
projectWealth = val;
}

public static double getPartnershipShare(int year) {

MultiKeyCoefficientMap map = partneredShare;
Object val = map.getValue(year);
if (val == null)
val = extendRateTimeSeries(year, map);
return ((Number) val).doubleValue();
}

public static double getSocialCarePolicyValue(int year, String param) {

Object val = socialCarePolicy.getRowColumnValue(year, param);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/simpaths/experiment/SimPathsMultiRun.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class SimPathsMultiRun extends MultiRun {

public static boolean executeWithGui = true;

private static int maxNumberOfRuns = 3;
private static int maxNumberOfRuns = 50;

private static String countryString;
private static int startYear;
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/simpaths/model/PartnershipAlignment.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import microsim.engine.SimulationEngine;
import simpaths.data.IEvaluation;
import simpaths.data.Parameters;
import simpaths.model.enums.Dcpst;

import java.util.Set;

Expand Down Expand Up @@ -30,7 +31,7 @@ public PartnershipAlignment(Set<Person> persons, double partnershipAdjustment) {
this.model = (SimPathsModel) SimulationEngine.getInstance().getManager(SimPathsModel.class.getCanonicalName());
this.persons = persons;
this.partnershipAdjustment = partnershipAdjustment;
targetAggregateShareOfPartneredPersons = 0.38; // TODO: List of targets by year should be provided through Excel file policy parameters.xlsx
targetAggregateShareOfPartneredPersons = Parameters.getPartnershipShare(model.getYear());
}

/**
Expand All @@ -48,6 +49,11 @@ public PartnershipAlignment(Set<Person> persons, double partnershipAdjustment) {
@Override
public double evaluate(double[] args) {

model.clearPersonsToMatch();
persons.stream()
.filter(person -> person.getDag() >= Parameters.MIN_AGE_COHABITATION)
.forEach(person -> person.evaluatePartnershipDissolution());

adjustPartnerships(args[0]);

double error = targetAggregateShareOfPartneredPersons - evalAggregateShareOfPartneredPersons();
Expand All @@ -69,7 +75,7 @@ private double evalAggregateShareOfPartneredPersons() {
.count();

long numPersonsPartnered = persons.stream()
.filter(Person::hasTestPartner)
.filter(person -> (person.hasTestPartner() || (person.getDcpst().equals(Dcpst.Partnered)) && !person.hasLeftPartnerTest()))
.count();

return numPersonsWhoCanHavePartner > 0
Expand All @@ -90,7 +96,7 @@ private double evalAggregateShareOfPartneredPersons() {
private void adjustPartnerships(double newPartnershipAdjustment) {
persons.stream()
.filter(person -> person.getDag() >= Parameters.MIN_AGE_COHABITATION)
.forEach(person -> person.evaluatePartnership(newPartnershipAdjustment));
.forEach(person -> person.evaluatePartnershipFormation(newPartnershipAdjustment));

// "Fake" union matching (not modifying household structure) here
model.unionMatching(true);
Expand Down
110 changes: 72 additions & 38 deletions src/main/java/simpaths/model/Person.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight,
@Transient
private double drawProvCareHours;
@Transient
private double drawPartnership; // Used with the partnership alignment process
private double drawPartnershipFormation, drawPartnershipDissolution; // Used with the partnership alignment process

//Sedex is an indicator for leaving education in that year
@Enumerated(EnumType.STRING)
Expand All @@ -193,7 +193,9 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight,
@Transient
private boolean toBePartnered;
@Transient
private boolean hasTestPartner; // Used in partnership alignment process. Indicates that this person has found partner in a test run of union matching.
private boolean hasTestPartner;
@Transient
private boolean leftPartnerTest; // Used in partnership alignment process. Indicates that this person has found partner in a test run of union matching.
@Transient
private Person partner;
@Column(name="idpartner")
Expand Down Expand Up @@ -461,7 +463,8 @@ public Person(Long id) {
educationInnov = new Random(SimulationEngine.getRnd().nextLong());
labourSupplyInnov = new Random(SimulationEngine.getRnd().nextLong());
labourSupplySingleDraw = labourSupplyInnov.nextDouble();
drawPartnership = -9;
drawPartnershipFormation = -9;
drawPartnershipDissolution = -9;
}

//For use with creating new people at the minimum Age who enter the simulation during UpdateMaternityStatus after fertility has been aligned
Expand Down Expand Up @@ -1239,25 +1242,75 @@ public void evaluateSocialCareProvide(double probitAdjustment) {
}
}

public void evaluatePartnership(double probitAdjustment) {
protected void considerCohabitation() {
toBePartnered = false;
if (drawPartnership < 0.) {
drawPartnership = cohabitInnov.nextDouble();
double probitAdjustment = 0.;
if (drawPartnershipFormation < 0.) {
drawPartnershipFormation = cohabitInnov.nextDouble();
}
if (model.isAlignCohabitation()) {
probitAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.PartnershipAdjustment);
}

if (model.getCountry() == Country.UK && dag >= Parameters.MIN_AGE_COHABITATION) {
if (partner == null) {
if (dag <= 29 && les_c4 == Les_c4.Student && !leftEducation) {
double score = Parameters.getRegPartnershipU1a().getScore(this, Person.DoublesVariables.class);
double prob = Parameters.getRegPartnershipU1a().getProbability(score + probitAdjustment);
toBePartnered = drawPartnershipFormation < prob;
} else if ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student)) {
double score = Parameters.getRegPartnershipU1b().getScore(this, Person.DoublesVariables.class);
double prob = Parameters.getRegPartnershipU1b().getProbability(score + probitAdjustment);
toBePartnered = drawPartnershipFormation < prob;
}
if (toBePartnered) model.getPersonsToMatch().get(dgn).get(getRegion()).add(this);
} else if (partner != null && dgn == Gender.Female && ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student))) {
if (cohabitInnov.nextDouble() < Parameters.getRegPartnershipU2b().getProbability(this, Person.DoublesVariables.class)) leavePartner();
}
} else if (model.getCountry() == Country.IT && dag >= Parameters.MIN_AGE_COHABITATION) {
if (partner == null) {
if ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student)) {
toBePartnered = (cohabitInnov.nextDouble() < Parameters.getRegPartnershipITU1().getProbability(this, Person.DoublesVariables.class));
if (toBePartnered) model.getPersonsToMatch().get(dgn).get(getRegion()).add(this);
}
} else if (partner != null && dgn == Gender.Female && ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student))) {
if (cohabitInnov.nextDouble() < Parameters.getRegPartnershipITU2().getProbability(this, Person.DoublesVariables.class)) leavePartner();
}
}
}

public void evaluatePartnershipFormation(double probitAdjustment) {
toBePartnered = false; // Reset variable indicating if individual wants to find a partner
hasTestPartner = false; // Reset variable indicating if individual has partner for the purpose of matching
if (drawPartnershipFormation < 0.) {
drawPartnershipFormation = cohabitInnov.nextDouble();
}

if (model.getCountry() == Country.UK && dag >= Parameters.MIN_AGE_COHABITATION && partner == null) {
if (dag <= 29 && les_c4 == Les_c4.Student && !leftEducation) {
double score = Parameters.getRegPartnershipU1a().getScore(this, Person.DoublesVariables.class);
double prob = Parameters.getRegPartnershipU1a().getProbability(score + probitAdjustment);
toBePartnered = drawPartnership < prob;
toBePartnered = drawPartnershipFormation < prob;
} else if ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student)) {
double score = Parameters.getRegPartnershipU1b().getProbability(this, Person.DoublesVariables.class);
double score = Parameters.getRegPartnershipU1b().getScore(this, Person.DoublesVariables.class);
double prob = Parameters.getRegPartnershipU1b().getProbability(score + probitAdjustment);
toBePartnered = drawPartnership < prob;
toBePartnered = drawPartnershipFormation < prob;
}
}

if (toBePartnered) {
model.getPersonsToMatch().get(dgn).get(getRegion()).add(this);
}
}

if (toBePartnered) {
model.getPersonsToMatch().get(dgn).get(getRegion()).add(this);
public void evaluatePartnershipDissolution() {
leftPartnerTest = false;
if (drawPartnershipDissolution < 0.) {
drawPartnershipDissolution = cohabitInnov.nextDouble();
}
if ((partner != null) && dgn == Gender.Female && ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student))) {
if (drawPartnershipDissolution < Parameters.getRegPartnershipU2b().getProbability(this, Person.DoublesVariables.class)) {
setLeftPartnerTest(true);
}
}
}
Expand Down Expand Up @@ -1320,33 +1373,6 @@ protected void leavingSchool() {
}


protected void considerCohabitation() {
toBePartnered = false;

if (model.getCountry() == Country.UK && dag >= Parameters.MIN_AGE_COHABITATION) {
if (partner == null) {
if (dag <= 29 && les_c4 == Les_c4.Student && !leftEducation) {
toBePartnered = (cohabitInnov.nextDouble() < Parameters.getRegPartnershipU1a().getProbability(this, Person.DoublesVariables.class));
} else if ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student)) {
toBePartnered = (cohabitInnov.nextDouble() < Parameters.getRegPartnershipU1b().getProbability(this, Person.DoublesVariables.class));
}
if (toBePartnered) model.getPersonsToMatch().get(dgn).get(getRegion()).add(this);
} else if (partner != null && dgn == Gender.Female && ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student))) {
if (cohabitInnov.nextDouble() < Parameters.getRegPartnershipU2b().getProbability(this, Person.DoublesVariables.class)) leavePartner();
}
} else if (model.getCountry() == Country.IT && dag >= Parameters.MIN_AGE_COHABITATION) {
if (partner == null) {
if ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student)) {
toBePartnered = (cohabitInnov.nextDouble() < Parameters.getRegPartnershipITU1().getProbability(this, Person.DoublesVariables.class));
if (toBePartnered) model.getPersonsToMatch().get(dgn).get(getRegion()).add(this);
}
} else if (partner != null && dgn == Gender.Female && ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student))) {
if (cohabitInnov.nextDouble() < Parameters.getRegPartnershipITU2().getProbability(this, Person.DoublesVariables.class)) leavePartner();
}
}
}


private void giveBirth() { //To be called once per year after fertility alignment

if(toGiveBirth) { //toGiveBirth is determined by fertility alignment (in the model class)
Expand Down Expand Up @@ -4362,4 +4388,12 @@ public void setHasTestPartner(boolean hasTestPartner) {
this.hasTestPartner = hasTestPartner;
}

public boolean hasLeftPartnerTest() {
return leftPartnerTest;
}

public void setLeftPartnerTest(boolean leftPartnerTest) {
this.leftPartnerTest = leftPartnerTest;
}

}
11 changes: 6 additions & 5 deletions src/main/java/simpaths/model/SimPathsModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,6 @@ public void buildSchedule() {
yearlySchedule.addEvent(this, Processes.CohabitationRegressionAlignment);
yearlySchedule.addCollectionEvent(persons, Person.Processes.ConsiderCohabitation);

// TODO: new partnership alignment routine should be here. It will adjust the number of people who want to cohabit, perform test union matching, and repeat until satisfactory number of unions has been created.
// Final adjusted probit will be then used to run consider cohabitation for the final time and perform union matching

// C: Union matching
yearlySchedule.addEvent(this, Processes.UnionMatching);
yearlySchedule.addCollectionEvent(benefitUnits, BenefitUnit.Processes.UpdateOccupancy);
Expand Down Expand Up @@ -1836,7 +1833,7 @@ private void socialCareMarketClearning() {
private void partnershipAlignment() {
double partnershipAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.PartnershipAdjustment); // Initial values of adjustment to be applied to considerCohabitation probit
PartnershipAlignment partnershipAlignment = new PartnershipAlignment(persons, partnershipAdjustment);
RootSearch search = getRootSearch(partnershipAdjustment, partnershipAlignment, 5.0E-2, 5.0E-2); // epsOrdinates and epsFunction determine the stopping condition for the search. For partnershipAlignment error term is the difference between target and observed share of partnered individuals.
RootSearch search = getRootSearch(partnershipAdjustment, partnershipAlignment, 1.0E-2, 1.0E-2); // epsOrdinates and epsFunction determine the stopping condition for the search. For partnershipAlignment error term is the difference between target and observed share of partnered individuals.
if (search.isTargetAltered()) {
Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.PartnershipAdjustment); // If adjustment is altered from the initial value, update the map
System.out.println("Adjustment value was " + search.getTarget()[0]);
Expand Down Expand Up @@ -3224,6 +3221,10 @@ public void setCollector(SimPathsCollector collector) {
this.collector = collector;
}

public boolean isAlignCohabitation() {
return alignCohabitation;
}


/**
*
Expand Down Expand Up @@ -3342,7 +3343,7 @@ private static void populateTaxdbReferences() {
}
}

private void clearPersonsToMatch() {
public void clearPersonsToMatch() {

for (Gender gender: Gender.values()) {
for (Region region: Region.values()) {
Expand Down

0 comments on commit 874c257

Please sign in to comment.