@@ -95,6 +95,8 @@ public class BenefitUnit implements EventListener, IDoubleSource, Weight, Compar
9595 @ Transient ArrayList <Triple <Les_c7_covid , Double , Integer >> covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale = new ArrayList <>(); // This ArrayList stores monthly values of labour market states and gross incomes, to be sampled from by the LabourMarket class, for the female member of the benefit unit
9696
9797 @ Transient Innovations innovations ;
98+ @ Transient private Double lastLabourInnov ;
99+ @ Transient private Integer lastYear ;
98100
99101 @ Transient private Integer yearLocal ;
100102 @ Transient private Occupancy occupancyLocal ;
@@ -153,7 +155,7 @@ public BenefitUnit(Long id, long seed) {
153155 key = new PanelEntityKey (id ); //Sets up key
154156
155157 this .seed = seed ;
156- innovations = new Innovations (9 , seed );
158+ innovations = new Innovations (9 , 1 , seed );
157159
158160 this .numberChildrenAll_lag1 = 0 ;
159161 this .numberChildren02_lag1 = 0 ;
@@ -1108,7 +1110,28 @@ protected void updateLabourSupplyAndIncome() {
11081110 }
11091111
11101112 //Sample labour supply from possible labour (pairs of) values
1111- double labourInnov = innovations .getDoubleDraw (5 );
1113+ double labourInnov = 0 ;
1114+
1115+ // Check if:
1116+ // - single occupant is employed
1117+ // - or male of couple is employed
1118+ // - or male is not at risk of work and female is employed
1119+ // -> then persist employment at prob_{persist_employment}
1120+ // Otherwise
1121+ // -> persist unemployment at prob_{persist_unemployment}
1122+
1123+ if (occupancy .Single_Male .equals (occupancy ) && male .atRiskOfWork () && male .getEmployed () == 1 ) {
1124+ labourInnov = getLabourInnovation (Parameters .labour_innovation_employment_persistence_probability );
1125+ } else if (occupancy .Single_Female .equals (occupancy ) && female .atRiskOfWork () && female .getEmployed () == 1 ) {
1126+ labourInnov = getLabourInnovation (Parameters .labour_innovation_employment_persistence_probability );
1127+ } else if (occupancy .equals (Occupancy .Couple ) &&
1128+ ((male .atRiskOfWork () && male .getEmployed () == 1 ) ||
1129+ (!male .atRiskOfWork () && female .atRiskOfWork () && female .getEmployed () == 1 ))) {
1130+ labourInnov = getLabourInnovation (Parameters .labour_innovation_employment_persistence_probability );
1131+ } else {
1132+ labourInnov = getLabourInnovation (Parameters .labour_innovation_notinemployment_persistence_probability );
1133+ }
1134+
11121135 try {
11131136 MultiKeyMap <Labour , Double > labourSupplyUtilityRegressionProbabilitiesByLabourPairs = convertRegressionScoresToProbabilities (labourSupplyUtilityRegressionScoresByLabourPairs );
11141137 labourSupplyChoice = ManagerRegressions .multiEvent (labourSupplyUtilityRegressionProbabilitiesByLabourPairs , labourInnov );
@@ -1529,6 +1552,30 @@ public enum Regressors {
15291552 MaleEduH_30 ,
15301553 MaleEduM_40 ,
15311554 MaleEduH_40 ,
1555+ MaleEduM_1 ,
1556+ MaleEduH_1 ,
1557+ MaleEduM_2 ,
1558+ MaleEduH_2 ,
1559+ MaleEduM_3 ,
1560+ MaleEduH_3 ,
1561+ MaleEduM_4 ,
1562+ MaleEduH_4 ,
1563+ FemaleEduM_10 ,
1564+ FemaleEduH_10 ,
1565+ FemaleEduM_20 ,
1566+ FemaleEduH_20 ,
1567+ FemaleEduM_30 ,
1568+ FemaleEduH_30 ,
1569+ FemaleEduM_40 ,
1570+ FemaleEduH_40 ,
1571+ FemaleEduM_1 ,
1572+ FemaleEduH_1 ,
1573+ FemaleEduM_2 ,
1574+ FemaleEduH_2 ,
1575+ FemaleEduM_3 ,
1576+ FemaleEduH_3 ,
1577+ FemaleEduM_4 ,
1578+ FemaleEduH_4 ,
15321579 MaleLeisure_dnc ,
15331580 FemaleLeisure_dnc ,
15341581 MaleLeisure_dnc02 ,
@@ -2416,6 +2463,78 @@ public double getDoubleValue(Enum<?> variableID) {
24162463 case MaleEduH_40 -> {
24172464 return (getMale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getMale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
24182465 }
2466+ case MaleEduM_1 -> {
2467+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TEN ) && getMale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2468+ }
2469+ case MaleEduH_1 -> {
2470+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TEN ) && getMale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2471+ }
2472+ case MaleEduM_2 -> {
2473+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TWENTY ) && getMale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2474+ }
2475+ case MaleEduH_2 -> {
2476+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TWENTY ) && getMale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2477+ }
2478+ case MaleEduM_3 -> {
2479+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .THIRTY ) && getMale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2480+ }
2481+ case MaleEduH_3 -> {
2482+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .THIRTY ) && getMale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2483+ }
2484+ case MaleEduM_4 -> {
2485+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getMale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2486+ }
2487+ case MaleEduH_4 -> {
2488+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getMale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2489+ }
2490+ case FemaleEduM_10 -> {
2491+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .TEN ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2492+ }
2493+ case FemaleEduH_10 -> {
2494+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .TEN ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2495+ }
2496+ case FemaleEduM_20 -> {
2497+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .TWENTY ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2498+ }
2499+ case FemaleEduH_20 -> {
2500+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .TWENTY ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2501+ }
2502+ case FemaleEduM_30 -> {
2503+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .THIRTY ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2504+ }
2505+ case FemaleEduH_30 -> {
2506+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .THIRTY ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2507+ }
2508+ case FemaleEduM_40 -> {
2509+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2510+ }
2511+ case FemaleEduH_40 -> {
2512+ return (getMale () != null && getFemale () != null && getMale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2513+ }
2514+ case FemaleEduM_1 -> {
2515+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TEN ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2516+ }
2517+ case FemaleEduH_1 -> {
2518+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TEN ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2519+ }
2520+ case FemaleEduM_2 -> {
2521+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TWENTY ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2522+ }
2523+ case FemaleEduH_2 -> {
2524+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .TWENTY ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2525+ }
2526+ case FemaleEduM_3 -> {
2527+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .THIRTY ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2528+ }
2529+ case FemaleEduH_3 -> {
2530+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .THIRTY ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2531+ }
2532+ case FemaleEduM_4 -> {
2533+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getFemale ().getDeh_c3 ().equals (Education .Medium )) ? 1. : 0. ;
2534+ }
2535+ case FemaleEduH_4 -> {
2536+ return (getMale () != null && getFemale () != null && getFemale ().getLabourSupplyWeekly ().equals (Labour .FORTY ) && getFemale ().getDeh_c3 ().equals (Education .High )) ? 1. : 0. ;
2537+ }
24192538 case MaleLeisure_dnc02 -> {
24202539 return (Parameters .HOURS_IN_WEEK - getMale ().getLabourSupplyHoursWeekly ()) * getIndicatorChildren (0 ,1 ).ordinal ();
24212540 }
@@ -3646,4 +3765,55 @@ public void removeMember(Person member) {
36463765 }
36473766
36483767 public static void setBenefitUnitIdCounter (long id ) {benefitUnitIdCounter = id ;}
3768+
3769+ /**
3770+ * Calculates the labour innovation value for the current period with persistence.
3771+ *
3772+ * This method implements a persistence mechanism for labour innovations where there's
3773+ * a probability that the previous period's innovation will persist into the current period.
3774+ * A new innovation is drawn each period, but it's only used with probability (1 - persistenceProbability).
3775+ *
3776+ * The persistence mechanism works as follows:
3777+ * 1. Draw a new potential innovation value
3778+ * 2. Draw a random number to determine if we should use the new value or persist with the old one
3779+ * 3. If it's the first period or there was a gap in years, use the new innovation
3780+ * 4. Otherwise, use the persistence probability to decide between new and old values
3781+ *
3782+ * @param persistenceProbability The probability (between 0 and 1) that the previous period's
3783+ * innovation will persist. A value of 0 means always use new innovations,
3784+ * while 1 means always keep the old innovation.
3785+ * @return The labour innovation value for this period
3786+ */
3787+ private double getLabourInnovation (double persistenceProbability ) {
3788+
3789+ double newLabourInnovation = innovations .getDoubleDraw (5 );
3790+
3791+ // persistenceRandomDraw - random value to determine if we keep old innovation
3792+ double persistenceRandomDraw = innovations .getDoubleDraw (6 );
3793+
3794+ int currentYear = model .getYear ();
3795+
3796+ // Initialize on first call
3797+ if (lastLabourInnov == null || lastYear == null ) {
3798+ lastLabourInnov = newLabourInnovation ;
3799+ lastYear = currentYear ;
3800+ return newLabourInnovation ;
3801+ }
3802+
3803+ double labourInnov ;
3804+ if (persistenceRandomDraw < persistenceProbability ) {
3805+ labourInnov = lastLabourInnov ;
3806+ } else {
3807+ labourInnov = newLabourInnovation ;
3808+ }
3809+
3810+ // Store values for next period
3811+ lastLabourInnov = labourInnov ;
3812+ lastYear = currentYear ;
3813+
3814+ return labourInnov ;
3815+
3816+
3817+
3818+ }
36493819}
0 commit comments