****************************************************************************** * LESLIE: v1.0, Mar. 25, 2026. Computes one-, two-sexes, and multistate * * population projections using extended Leslie matrices. Projections * * incorporate future trajectories of fertility and survival, net migrants, * * derive intrinsic rates, stable equivalent age structures, the net rep. * * rate (NRR), mean age of the maternity schedule, years of population growth * * before declining, TFR, e0, pop. momentum, and others. The program also * * generates graphs of future asfr and survival probabilities * * of the actual, intrinsic and stable equivalent age structures. * * * First variable of the dataset must have the lower limit of the age group * * as observations. * * * Author: Jeronimo O. Muniz, PhD. Professor of Sociology at UFMG, Brazil * ****************************************************************************** /* leslie.ado – Copyright (C) 2026 Jeronimo Oliveira Muniz This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY... */ window menu clear window menu append item "stUserStatistics" /// "Demographic projections (&leslie)" "db leslie" if `c(version)' > 18 { //sets the graph scheme of newer Stata versions to be backward compatible with the program, written in version 15 set scheme stsj } *! 1.0.0 JOM, 25mar2026 program define leslie, rclass version 15 //Program developed in this version of Stata syntax, Period(integer) [, SRb(real 1.05) male total l0(integer 100000) /// ExtraT(numlist max=2) Two Fert(numlist>0 max=1) Baseline(integer 0) /// PLace(string) SURv(numlist>40 max=2 miss) SIgma(numlist>0 max=2) /// nmr(string) mig1(string) mig2 MUltistate Nomobility Stable SUmmary /// Tolerance(real 1e-6) Keyfitz Ygual(integer 14) GRopts(string asis)] tempname radix qui matrix input `radix'= (`period') mata: period= st_matrix(st_local("radix")) loc period= `radix'[1,1]+1 mata: n = st_data(.,1)[3]-st_data(.,1)[2] // interval length mata: st_local("n", strofreal(n)) //local `n' mata: a = st_data(.,1):+(n/2) // age-group midpoints mata: p = st_data(.,2) // population count by age ******************************************************************************* *Error messages: *if period(integer) is higher than 99 or lower than 1 capture { local z= `period'-1 if (`z'>99 | `z'<1) error 103 } if _rc == 103 { display as err "{p}" di "Please specify a number between 1 and 99 in {opt period()}." di "If you requested more than 99 projections in your syntax of" di "{cmd: leslie}, remember J. M. Keynes's (1923) words: 'The long run is" di "a misleading guide to current affairs. In the long run we are all dead'." exit 103 } *if dataset has just one population but the user adds option "two" capture { qui ds tokenize `r(varlist)' duplicates report `1' if "`two'"=="two" & (`r(unique_value)'==`r(N)') error 503 } if _rc == 503 { display as err "{p}" di "Your dataset seems to have just one population." di "Aren't you equivocally adding option {opt two} to the command line?" exit 503 } *if dataset has just one population but the user adds option "multistate" capture { qui ds tokenize `r(varlist)' duplicates report `1' if "`multistate'"=="multistate" & (`r(unique_value)'==`r(N)') error 3300 } if _rc == 3300 { display as err "{p}" di "Your dataset seems to have just one population. Aren't you equivocally" di " adding option {opt multistate} to the command line?" exit 3300 } *if dataset has more than one population but the user forgets option "two" capture { qui ds tokenize `r(varlist)' duplicates report `1' if "`two'"=="" & "`multistate'"=="" & (`r(unique_value)'<`r(N)') error 119 } if _rc == 119 { display as err "{p}" di "Your dataset seems to have more than one population." di "Aren't you forgetting to add option {opt two} or {opt multistate}?" exit 119 } *if data is probably multistate but that option is not included capture{ qui des if `r(k)'>4 & "`multistate'"=="" error 3200 } if _rc== 3200 { display as err "{p}" di "Your dataset has more than four variables (or columns). If it is" di "{opt multistate} please add this option to your command line." exit 3200 } *if data is for two-sex populations but multistate is included capture { qui des if "`multistate'"=="multistate" & `r(k)'==4 error 3300 } if _rc== 3300 { display as err "{p}" di "Your dataset is not adequate for multistate analysis. Please remove" di "the {opt multistate} option from your command line." exit 3300 } *just one value within extraT() but "two" option capture { local count: word count `extraT' if "`two'"=="two" & "`extraT'"!= "" & `count'<2 error 3000 } if _rc== 3000 { display as err "{p}" di "You must specify two values within the {opt extraT()} option if" di "you request the {opt two} option." exit 3000 } *if the "keyfitz" option is specified with the "multistate" option capture { if ("`multistate'"!=""| "`two'"!="") & "`keyfitz'"!="" error 3000 } if _rc == 3000 { display as err "{p}" di "Keyfitz's Delta cannot be used as a criterion of distance to stability" di "when the {opt multistate} or {opt two} options are also specified." exit 3000 } *if the "keyfitz" option is specified without the "summary" option capture { if "`keyfitz'"!="" & "`summary'"=="" error 3000 } if _rc == 3000 { display as err "{p}" di "The {opt keyfitz} option must be jointly specified with" di " the {opt summary} option." exit 3000 } *if the "tolerance" option is specified without the "summary" option capture { if "`tolerance'"!="1.00000000000e-06" & "`summary'"=="" error 3000 } if _rc == 3000 { display as err "{p}" di "The {it: default} level of tolerance to achieve stability is set to 1e-6." di " Please specify the {opt tolerance()} and {opt summary} options together" di " if you want to change this level." exit 3000 } *just one value in surv(), but "two" option is specified capture { local s_count: word count `surv' if "`two'"!="" & "`surv'"!="" & `s_count'<2 error 3000 } if _rc== 3000 { display as err "{p}" di "Specify two consecutive values in {opt surv()} (i.e., female and" di "male expected life expectancies) when you simultaneously specify the" di "{opt two} option." exit 3000 } *if mig2 is requested without mig1() capture { if "`mig2'"== "mig2" & "`mig1'"== "" error 3000 } if _rc== 3000 { display as err "{p}" di "The {opt mig2} option must be simultaneously entered with the" di "{opt mig1()} option." exit 3000 } *if the "extraT()" option is specified with the "multistate" option capture { if "`multistate'"!="" & "`extraT'"!="" error 3000 } if _rc == 3000 { display as err "{p}" di "{opt extraT()} cannot be used" di "when the {opt multistate} option is also specified." exit 3000 } *if the "mig1()" option is specified with the "multistate" option capture { if "`multistate'"!="" & "`mig1'"!="" error 601 } if _rc == 601 { display as err "{p}" di "The {opt mig1()} option cannot be requested" di "when the {opt multistate} option is also specified." exit 601 } *if the "nomobility" option is specified without the "multistate" option capture { if "`multistate'"=="" & "`nomobility'"!="" error 601 } if _rc == 601 { display as err "{p}" di "The {opt nomobility} option can only be requested " di "when the {opt multistate} option is also specified." exit 601 } *if "male" and "total" options are simultaneously specified capture { if "`male'"!="" & "`total'"!="" error 119 } if _rc == 119 { display as err "{p}" di "Are you projecting the single {opt male} population or the {opt total}" di " population (combining females and males in a single vector)?" di " You cannot specify both options at the same time." exit 119 } *if "baseline()" and "place()" options are specified without each other capture { if ("`baseline'"!="0" & "`place'"=="" & ("`fert'"=="" & "`surv'"=="")) | /// ("`baseline'"=="0" & "`place'"!="") | ("`baseline'"!="0" & /// "`place'"!="" & "`fert'"!="") error 119 } if _rc == 119 { display as err "{p}" di "You must simultaneously specify the {opt baseline()} and {opt fert()}" di " (or {opt surv()}) options {bf:OR} {opt baseline()} and {opt place()} to" di " predict the future trajectory of fertility (or survival) using the" di " probabilistic median variant of the United Nations (2024)." exit 119 } *if "baseline()" and `baseline'+(`period'-1)*`n'< 2023 capture { if "`baseline'"!="0" & (`baseline'+(`period'-1)*`n')<2024 error 119 } if _rc == 119 { display as err "{p}" di "If you specify {opt baseline()}, your final projection year, derived" di " from {opt period()}, must be later than 2024." exit 119 } *if "baseline()", "place()" and "surv()" are simultaneusouly defined capture { if "`baseline'"!="0" & "`place'"!="" & ("`surv'"!="." & "`surv'"!="") /// & "`two'"=="" error 119 } if _rc== 119 { display as err "{p}" di "Set {opt surv(.)} to choose the life expectancy expected in the last" di "projection period from the United Nations (2024)." di " Alternatively, if you set a future value in the {opt surv()} option," di " do not specify the {opt place()} option." exit 119 } *if "surv(.)" & "baseline()" OR just "surv(.)" capture { if ("`surv'"=="." | "`surv'"==". .") & "`baseline'"=="0" & "`place'"=="" /// | ("`surv'"=="." | "`surv'"==". .") & "`baseline'"!="0" & /// "`place'"=="" error 119 } if _rc==119 { display as err "{p}" di "Enter a valid value for life expectancy in the {opt surv()} option." exit 119 } ******************************************************************************* if "`multistate'"=="" { mata: L = st_data(.,3)/`l0' } if "`two'" == "" & "`multistate'"=="" { mata: T= flipud(runningsum(flipud(L))) //running sum of L(x) } if "`two'" != "" & "`multistate'"=="" { mata: T=J(length(L),1,0) // females in the top, males in the bottom mata: T[1..length(L)/2]= flipud(runningsum(flipud(L[1..length(L)/2]))) mata: T[(length(L)/2)+1..length(L)]= /// flipud(runningsum(flipud(L[(length(L)/2)+1..length(L)]))) } *ERROR msg: the last value of T must be lower than in the previous age group capture { mata: st_local("Tlast", strofreal(T[length(T)])) if "`two'"== "two" { mata: st_local("Tlastf", strofreal(T[length(T)/2])) } tokenize `extraT' if ("`extraT'"!="" & "`two'"=="") & `1'>`Tlast' error 3000 if ("`extraT'"!="" & "`two'"=="two") & `2'>`Tlast' error 3000 if ("`extraT'"!="" & "`two'"=="two") & `1'>`Tlastf' error 3000 } if _rc== 3000 { display as err "{p}" di "The extra value(s) of {it:T} specified for the open-ended age group, typed" di " within the {opt extraT()} option, cannot be higher than" di " the value of {it:T} observed in the previous/last age group." di " To verify the value of {it:T} in the last age group type: {cmd:.mata T}." exit 3000 } *Maternity rates (female births) mata: f = st_data(.,4) // ASFRs mata: m= f/(1+`srb') // The default is srb= 105/100, for female proj. if "`male'"!="" { mata: m= f*(`srb'/(1+`srb')) } //The default sets srb= 100/105= 0.95238095 for male proj. if "`total'"!="" { mata: m= f } //For both sexes combined in a single total pop., sets srb=0. if "`two'" == "" & "`multistate'"=="" { mata: nrr= sum(L:*m) //Net reproduction rate } if "`two'" != "" & "`multistate'"=="" { mata: mm= f/(1+1/`srb') //male-fertility rate (male births), male-dominant proj. mata: fnrr= sum(L[1..(length(L)/2)]:*m[1..(length(L)/2)]) //females mata: mnrr= sum(L[(length(L)/2)+1..length(L)]:*mm[1..(length(L)/2)]) //males } ************* *PROJECTIONS* ************* if "`two'" == "" & "`multistate'"=="" { mata: M= Leslie(L,m) // Leslie(1945) matrix, one-sex if "`extraT'"!= "" { mata: M[rows(M),cols(M)-1]= (T[length(T)]-`extraT')/L[length(L)-1] mata: M[rows(M),cols(M)]= `extraT'/((T[length(T)]-`extraT')+`extraT') } } if "`two'" != "" { //no migration *Female block mata: fM=Leslie(L[1..length(L)/2],m[1..length(L)/2]) if "`extraT'"!= "" { tokenize `extraT' mata: fM[rows(fM),cols(fM)-1]= (T[length(T)/2]-`1')/L[length(L)/2-1] mata: fM[rows(fM),cols(fM)]= `1'/((T[length(T)/2]-`1')+`1') } //Male block mata: mM= Lesliem(L[1..length(L)/2],L[(length(L)/2)+1..length(L)],mm[1..length(L)/2]) if "`extraT'"!= "" { mata: mM[rows(mM),cols(mM)-1]= (T[length(T)]-`2')/L[length(L)-1] mata: mM[rows(mM),cols(mM)]= `2'/((T[length(T)]-`2')+`2') } mata: M= blockdiag(fM,mM) //Two-sex combined (without migration) mata: F_m= mM[1,.],J(1,cols(mM),0) mata: M[length(p)/2+1,.]= F_m // places male births to be multiplied by women } if "`nmr'"!="" { preserve qui use `nmr' mata: nmr= st_data(.,1) restore if "`two'" == "" { mata: P= diag(nmr) if "`mig2'" == "" { mata: M = M + P*M // replaces one-sex proj. matrix without mig. by one with mig. } *Approach 2: assumes that residual migrants are split over the proj. period * (referee's suggestion based on Preston et al 2001, 125-127). if "`mig2'" != "" { mata: M= M + M*P*M/2 + P*M/2 } } if "`two'" != "" { *Female migration block mata: Pf= diag(nmr[1..length(nmr)/2]) *Male migration block qui des mata: Pm= diag(nmr[length(nmr)/2+1..`r(N)']) *Matrices including migration, two-sexes *Approach1: adds migrants at the beggining of the interval if "`mig2'" == "" { loc size= `r(N)'/2 mata: Sm= mM-(F_m[1..`size']\J(`size'-1,`size',0)) // male survival matrix mata: M=blockdiag((I(`size')+Pf)*fM, Sm+Pm*mM) // two-sexes w/ net migration *Puts male births in lower left block to be multiplied by women mata: M[(`size'+1)..`r(N)',1..`size']= F_m[1..`size']\J(`size'-1,`size',0) } *Approach2: splits migrants over the proj. period, Preston et al(2001, 125-127) if "`mig2'" != "" { mata: Sm= mM-(F_m[1..`size']\J(`size'-1,`size',0)) // male survival matrix mata: M=blockdiag(fM, Sm) mata: M[(`size'+1)..`r(N)',1..`size']= F_m[1..`size']\J(`size'-1,`size',0) mata: M= M+ M*blockdiag(Pf*fM/2, Pm*mM/2)+ blockdiag(Pf*fM/2, Pm*mM/2) } } } if "`mig1'" != "" { preserve qui use `mig1' mata: op=st_data(.,1) //adds pop. in t-5 to Mata restore mata: res= p-(M*op) //Residual migrants from past pop. proj. forward mata: nmr=J(length(p),1,0) //Probs. of migration for age group x-n qui su if "`two'" == "" { *Net migration "RATES": Denominator represents proj. pop. (natural growth), * following Thomlinson (1962) and Johnson et al (2005) forval x=2/`r(N)' { mata: nmr[`x']=res[`x']/(M*op)[`x'] } *mata: nmr[`r(N)']=res[`r(N)']/((M*op)[`r(N)']) mata: nmr[1]= p[1]:/(M*op)[1]-1 //first element of the nmr vector (P matrix) *mata: mfert= (M[1,.]/rowsum(M[1,.])*res[1])':/(M*op) //Migrants' ASFR adj. *mata: P=Leslie2(nmr,mfert) mata: P= diag(nmr) *Matrices including migration, one-sex *Approach 1: adds migrants at at the start of the interval if "`mig2'" == "" { mata: M=M + P*M // replaces one-sex proj. matrix without mig. by one with mig. } *Approach 2: assumes that residual migrants are split over the proj. period * (referee's suggestion based on Preston et al 2001, 125-127). if "`mig2'" != "" { mata: M= M + M*P*M/2 + P*M/2 } } if "`two'" != "" { *Female migration block qui des loc size= `r(N)'/2 forval x=2/`size' { mata: nmr[`x']=res[`x']/(M*op)[`x'] } mata: nmr[1]= p[1]:/(M*op)[1]-1 mata: Pf= diag(nmr[1..length(nmr)/2]) *Male migration block loc sizem= (`r(N)'/2)+2 forval x=`sizem'/`r(N)' { mata: nmr[`x']=res[`x']/(M*op)[`x'] } mata: nmr[length(p)/2+1]= p[length(p)/2+1]:/(M*op)[length(p)/2+1]-1 mata: Pm= diag(nmr[length(nmr)/2+1..`r(N)']) *Matrices including migration, two-sexes *Approach1: adds migrants at the beggining of the interval if "`mig2'" == "" { mata: Sm= mM-(F_m[1..`size']\J(`size'-1,`size',0)) // male survival matrix mata: M=blockdiag((I(`size')+Pf)*fM, Sm+Pm*mM) // two-sexes w/ net migration *Puts male births in lower left block to be multiplied by women mata: M[(`size'+1)..`r(N)',1..`size']= F_m[1..`size']\J(`size'-1,`size',0) } *Approach2: splits migrants over the proj. period, Preston et al(2001, 125-127) if "`mig2'" != "" { mata: Sm= mM-(F_m[1..`size']\J(`size'-1,`size',0)) // male survival matrix mata: M=blockdiag(fM, Sm) mata: M[(`size'+1)..`r(N)',1..`size']= F_m[1..`size']\J(`size'-1,`size',0) mata: M= M+ M*blockdiag(Pf*fM/2, Pm*mM/2)+ blockdiag(Pf*fM/2, Pm*mM/2) } } } if "`multistate'" != "" { *Conversion of qxi (prob. that an individual in state i at age x will be in *state j at age x+n) to sij(x,n) - survivorship proportions: the proportion *of persons in state i of the model population between ages x and x+n who are in *state j exactly n years later. Note that sij(x,n) are the elements that will *be placed in the subdiagonal of the multistate Leslie matrix. *Step 1: age-specific transition matrices, P(x), a la Rogers (1995: 96) preserve if "`nomobility'" !="" { //zeros the transition probabilities in the dataset qui des loc last=`r(k)'-1 forval c=5/`last' { loc to `to' `c' } qui ds tokenize `r(varlist)' foreach var of local to { qui replace ``var''=0 } } qui des mata: rates= st_data(.,5..(`r(k)'-1)) mata: q= st_data(.,3) mata: v1= st_data(.,`r(k)') mata: info= panelsetup(v1,1) qui su loc max= `r(max)' // local macro for the number of states forval x=1/`r(max)' { mata pan`x'= panelsubmatrix(rates,`x',info)[.,1..`r(max)'] } clear forval x=1/`max' { getmata (var`x'*)=pan`x' } foreach var of varlist * { summ `var', meanonly if missing(r(mean)) drop `var' } if "`nomobility'" !="" { drop var1* } qui des forval x= 1/`r(N)' { mata: N`x'= N(colshape(st_data(`x',(1..st_nvar())),`max'-1)) //fun. N() mata: q`x'= diag(colshape(rowshape(q,`r(N)'),`r(N)')'[`x',.]) mata: P`x'= (N`x'-q`x')' mata: M`x'= 2/n*luinv(I(`max')+P`x')*(I(`max')-P`x') } loc j=`r(N)'-1 forval x=1/`j' { loc y = `x'+1 *Rogers (1995: 101) *mata: S`x'M = luinv(I(`max')+n/2*M`y')*(I(`max')-n/2*M`x') mata: S`x'P = (I(`max')+P`y')*P`x'*luinv(I(`max')+P`x') } restore *Step 2: calculation of survivorship ratios, S(x) mata: l1=diag(J(`max',1,`l0')) //puts the l0s from mu() in their proper place forval x=2/`r(N)' { loc y= `x'+1 loc z=`x'-1 mata: l`x'=P`z'*l`z' mata: l`y'= P`x'*l`x' mata: d`z'= l`z'-l`x' mata: d`x'= l`x'-l`y' mata: L`z'= luinv(M`z')*d`z' mata: L`x'=luinv(M`x')*d`x' mata: S`z'=L`x'*luinv(L`z') //same as S`x'P and S`x'M } *Calculation of L(x) in the last open-ended age group * Following Ortega(1982, 25) and UN(1956,23), apud Muniz(2023,footnote 6) mata: L`r(N)'= l`r(N)'*luinv(M`r(N)') *l`r(N)':*log10(l`r(N)') /*mata: values = J(0,0,.) mata: vectors = J(0,0,.) mata: eigensystem(l`r(N)', vectors, values) mata: L`r(N)'=vectors:*diag(log10(values))*luinv(vectors) */ if "`nomobility'"!= "" { //gets rid of 0 values to execute log10 mata: L`r(N)'= l`r(N)'*luinv(M`r(N)') *l`r(N)':*diag(log10(diagonal(l`r(N)'))) } *Calculation of S(x) in the next-to-last age group *mata: S`r(N)'P= I(`max')-n/2*(I(`max')+P`r(N)')*M`r(N)' //Rogers(1995:106) *mata: S`r(N)'P= L`r(N)'*luinv(L`r(N)'+L`j') mata: S`j'P= luinv(I(`max')+n/2*M`r(N)')*(I(`max')-n/2*M`j') *Re(L`r(N)':/(L`r(N)'+L`j')) *luinv(I(`max')+n/2*M`r(N)')*(I(`max')-n/2*M`j') mata: S`r(N)'P= S`j'P *diag(J(rows(S1P),cols(S1P),0)) //zero matrix *S`j'P *Step 3: Place the elements of S(x) in vectors/ matrices qui su loc cols=`r(max)' loc agel=`r(N)'/`r(max)' forvalues c=1/`cols' { local state `state' `c' } foreach a of local state { mata: s`a'=J(`agel', `r(max)',0) forval x=1/`agel' { mata: s`a'[`x',.]=S`x'P'[`a',.] } } mata: s=s1 forval a=2/`r(max)' { mata: s= s\s`a' //structured as v2 } mata: sd=s1[.,1] //pii in a single column vector similar to v3 forval a=2/`r(max)' { mata: sd= sd\s`a'[.,`a'] //structured as v2 } qui des mata: v2= st_data(.,(5..(`r(k)'-1))) mata: v3= st_data(.,3..4) //Mortality and reproduction Leslie matrices mata: v3[.,1]= 1:-(st_data(.,3)+rowsum(v2)) //Stayers' prob. of surv. in i mata: vpsurv= 1:-st_data(.,3) //prob. of surviving qui su ``r(k)'' forval x=1/`r(max)' { mata: surv`x'= panelsubmatrix(v3,`x',info)[.,1] //stayers prob of surv. in i mata: prsurv`x'=panelsubmatrix(vpsurv,`x',info)[.,1] //prob of surv. in i mata: sd`x'=panelsubmatrix(sd,`x',info)[.,1] mata: tft`x' =panelsubmatrix(v3,`x',info)[.,2] } mata: Mob= panelsubmatrix(s,1,info)[.,1] forval x=2/`r(max)' { mata: Mob= blockdiag(Mob, panelsubmatrix(sd,`x',info)[.,1]) //Surv. in diag. } mata: v2= Mob+editmissing(v2,0) //input for mobility matrices below qui su loc length= `r(N)'/`r(max)'-1 forval x=1/`r(max)' { mata: ave_tft`x'=J(length(tft`x'),1,.) forval z= 1/ `length' { mata: ave_tft`x'[`z']= (tft`x'[`z']+tft`x'[`z'+1]:*prsurv`x'[`z'+1])/2 } mata: ave_tft`x'= editmissing(ave_tft`x',0) //Average ASFR } *Mobility matrices qui ds tokenize "`r(varlist)'" qui su ``r(k)'' forval x=1/`r(max)' { forval y=1/`r(max)' { //ASFRs mata: M`x'`y' = diag(panelsubmatrix(s,`x',info)[.,`y']) mata: M`x'`y'[rows(M`x'`y')-1,cols(M`x'`y')] = /// M`x'`y'[rows(M`x'`y'),cols(M`x'`y')] mata: M`x'`y' = J(1,cols(M`x'`y'),0)\M`x'`y'[1..(cols(M`x'`y')-1),.] mata: mob`x'`y'=panelsubmatrix(v2,`x',info)[.,`y'] mata: M`x'`y'[1,.]= n/(1+`srb'):*(ave_tft`x':*prsurv`x'[1]:* /// mob`x'`y':/prsurv`x')' } } *Assembling block matrix with mobility matrices a *la Rogers(1966, 1968: 13, 1995:117, (A)) mata: Mmig= M11 forval i= 1/`r(max)' { forval j=1/`r(max)' { mata: Mmig= Mmig\ M`i'`j' } } mata: Mmig=Mmig[cols(M11)+1..rows(Mmig),.] mata: Mmig2=Mmig[1..rows(s),.] loc max=`r(N)'*(`r(max)'-1) forval l=`r(N)'(`r(N)')`max' { mata: Mmig2=Mmig2, Mmig[(`l'+1)..(`l'+`r(N)'),.] //Mobility matrices } mata: M=editmissing(Mmig2,0) } if "`multistate'" != "" & "`nomobility'" !="" { qui su forval x=1/`r(max)' { mata: M`x'=Lesliems(sd`x', prsurv`x', tft`x') } mata: Mb=M1 forval x=2/`r(max)' { mata: Mb=blockdiag(Mb, M`x') //Mortality and fertility Leslie matrices } mata: M=Mb } ************************************************************ *Last step of POPULATION PROJECTIONS: matrix multiplication* ************************************************************ *Assuming constant rates mata: fp=J(st_nobs(),`period',0) //creates a null matrix of future pops. mata: fp[.,1]=p /*if "`extraT'" == "" { mata: fp[st_nobs(),1]=p[st_nobs()]+p[st_nobs()-1] } if "`two'"!="" & "`extraT'"=="" { mata: fp[st_nobs(),1]=p[st_nobs()]+p[st_nobs()-1] mata: fp[st_nobs()/2,1]=p[st_nobs()/2]+p[st_nobs()/2-1] } */ if "`fert'" == "" { forval x=2/`period' { mata: fp[.,`x']=M*fp[.,`x'-1] } } ********************** *PROJECTION SCENARIOS* ********************** ********* *ONE-SEX* ********* /*FERTILITY: depends on the ultimate TFR level defined by the user and assumes that the change happens equally in all age groups (no change in the fertility pattern). The rhythm/speed of change is derived from the formula of compound interest rates.*/ if "`two'" == "" { if "`baseline'" =="0" & "`fert'" != "" { //constant ASFR drop over time mata: r_fert= (`fert'/(colsum(f)*n))^(1/period)-1 //compound interest rate mata: fF=J(period+1,cols(M),.) mata: fF[1,.]=M[1,.] // first row of projection matrix M forval x=2/`period' { // future net female ASFRs levels, same age pattern mata: fF[`x',.]=fF[`x'-1,.]+fF[`x'-1,.]*r_fert } *Conversion of fF values (i.e., first row of M) to ASFRs mata: mat_rate=flipud(fF') mata: start=diag0cnt(diag(select(mat_rate,a:>10)[.,1]))+1 mata: mat_rate[start,.]=flipud(fF')[start,.]:/L[1]*2 //last reproductive age mata: st_local("start", strofreal(start+1)) mata: start2=rows(fF')-diag0cnt(diag(select(fF',a:<50)[.,1])) mata: st_local("start2", strofreal(start2)) forval x=`start'/`start2' { mata: mat_rate[`x',.]=2*flipud(fF')[`x',.]:/L[1]-mat_rate[`x'-1,.]* /// flipud(L)[`x'-1]/flipud(L)[`x'] } mata: mat_rate=flipud(mat_rate) // future female ASFRs *Graph showing ASFR future scenarios mata: st_local("tfr", strofreal(colsum(f)*n, "%4.2f")) //current/first tfr mata: st_local("tfr2", strofreal(colsum(mat_rate[.,cols(mat_rate)])* /// (1+`srb')*n, "%4.2f")) //last tfr mata: st_local("fc_rate", strofreal(r_fert*100, "%4.2f")) //speed of change mata: st_local("interval", strofreal(n, "%4.0f")) //length of age group preserve forval x=1/`period' { //Generates variables of predicted ASFRs mata: st_store(.,st_addvar("float","fF`x'"), mat_rate[.,`x']:*(1+`srb')) } qui des //Graphs age structure of age-specific fertility rates loc pn=`r(k)' qui ds tokenize "`r(varlist)'" qui keep if `1'<=50 & `1'>=10 // restricts graph to reproductive ages loc last_p =`period'+1 line `5'-``pn'' `1', lwidth(vthick) /// || line ``pn'' `1', lp(dash_dot) lwidth(vthick) /// , graphregion(fcolor(white)) ytitle(ASFR) ti(Predicted Trajectory of Age /// Specific Fertility Rates) leg(on order(1 "Current" "period (TFR= `tfr')" /// `last_p' "Last" "period (TFR= `tfr2')") region(lc(%0)) pos(6) col(2) /// all) name(asfr, replace) note({it:Note}: Convergence speed corresponds /// to a `fc_rate'% change in TFR per `interval'-year period., span) `gropts' restore } if "`baseline'" != "0" { if "`place'" != "" & ("`surv'"=="" | "`surv'"==".") { //defines a final specific ASFR standard preserve use "wpp2024_median_fert.dta", replace loc fyear=`baseline'+(`period'-1)*`n' list Place Year TFR if Place== "`place'" & Year==`fyear', clean noobs qui putmata asfr_std=(asfr_10-asfr_50) if Place== "`place'" & /// Year==`fyear', replace restore mata: fasfr=J(1,rows(a),0) mata: fasfr[3..11]=asfr_std/1000*n } if "`fert'" != "" { //defines a final ASFR standard according to min(TFRt-TFR) preserve use "wpp2024_median_fert.dta", replace mata: st_local("n", strofreal(n)) loc fyear=`baseline'+(`period'-1)*`n' qui drop if Year!=`fyear' qui gen Abs_diff= abs(`fert'-TFR) sort Abs_diff list Place Year TFR Abs_diff in 1/5, clean qui gen asfr_std=1 in 1 // choosen pattern qui putmata asfr_std=(asfr_10-asfr_50) if asfr_std==1, replace restore mata: asfr_std=asfr_std/1000*n mata: asfr_std=asfr_std:/rowsum(asfr_std) //Shares of future TFR mata: fasfr=J(1,rows(a),0) mata: fasfr[3..11]=asfr_std*`fert' //future ultimate asfr borrowing // the age pattern from a place in the WPP with the closest TFR value } if "`fert'"!="" | ("`baseline'"!="0" & "`place'"!="" & /// "`surv'"=="." | "`surv'"== "") { mata: rfert=(fasfr':/(f*n)):^(1/period):-1 //age-specific growth rate of ASFR *Future trajectory of the first row of the Leslie matrix mata: fF=J(period+1,cols(M),.) mata: fF[1,.]=M[1,.] //female ASFR in the first period forval x=2/`period' { //future female ASFR levels, borrowed pattern mata: fF[`x',.]=editmissing(fF[`x'-1,.]+fF[`x'-1,.]:*rfert',0) } *ASFRs future trajectory mata: f_asfr=J(period+1,cols(fasfr),.) mata: f_asfr[1,.]=(f*n)' //female ASFR in the first period forval x=2/`period' { //future female ASFR levels, borrowed pattern mata: f_asfr[`x',.]=f_asfr[`x'-1,.]+f_asfr[`x'-1,.]:*rfert' } mata: f_asfr=editmissing(f_asfr',0) *Graph showing ASFR future scenarios mata: st_local("tfr", strofreal(colsum(f)*n, "%4.2f")) //current/first tfr mata: st_local("tfr2", strofreal(colsum(f_asfr[.,cols(f_asfr)]),"%4.2f")) //last tfr mata: st_local("fc_rate", strofreal(mean(rfert)*100, "%4.2f")) //speed of change mata: st_local("interval", strofreal(n, "%4.0f")) //length of age group preserve forval x=1/`period' { //Generates variables of predicted ASFRs mata: st_store(.,st_addvar("float","fF`x'"), f_asfr[.,`x']) } qui des //Graphs age structure of age-specific fertility rates loc pn=`r(k)' qui ds tokenize "`r(varlist)'" qui keep if `1'<=50 & `1'>=10 // restricts graph to reproductive ages loc last_p =`period'+1 line `5'-``pn'' `1', lwidth(vthick) /// || line ``pn'' `1', lp(dash_dot) lwidth(vthick) /// , graphregion(fcolor(white)) ytitle(ASFR) ti(Predicted Trajectory of Age /// Specific Fertility Rates) leg(on order(1 "Current" "period (TFR= `tfr')" /// `last_p' "Last" "period (TFR= `tfr2')") region(lc(%0)) pos(6) col(2) /// all) name(asfr, replace) note({it:Note}: Convergence speed: /// `fc_rate'% average change in TFR per `interval'-year period., span) `gropts' restore } } *Execute forward projections with varying net female ASFRs if ("`place'"!="" & "`surv'"=="") | "`fert'" != "" { forval x=2/`period' { //projections mata: M[1,.]= fF[`x',.] mata: fp[.,`x']= M*fp[.,`x'-1] //changing net female ASFRs } } } /*SURVIVAL: Calculation of future survival using a logistic curve based on three parameters: alfa, sigma and future life expectancy at birth. Sigma defines how steep the gains in survival will be. Higher values of sigma implies in increased survival at older ages, lower values implies higher gains in intermediate ages. Sigma, in other words, defines the rectangularization of the survival curve*/ *Gets final life expectancy from the World Population Prospects (WPP) file if "`two'" == "" & "`surv'"!="" & "`surv'"!="." & "`baseline'"!="0" /// & "`place'"=="" { preserve if "`male'"=="" { //if female use "wpp2024_median_e0F.dta", replace } if "`male'"!= "" { // if male use "wpp2024_median_e0M.dta", replace } if "`total'"!="" { //if total use "wpp2024_median_e0.dta", replace } loc fyear=`baseline'+(`period'-1)*`n' qui keep Index-Type e0_`fyear' qui gen Abs_diff= abs(e0_`fyear'-`surv') sort Abs_diff list Place e0_`fyear' in 1/5, clean restore } if "`two'" == "" & "`surv'"=="." & "`baseline'"!="0" & "`place'"!="" { preserve if "`male'"=="" { //if female use "wpp2024_median_e0F.dta", replace } if "`male'"!= "" { // if male use "wpp2024_median_e0M.dta", replace } if "`total'"!="" { //if total use "wpp2024_median_e0.dta", replace } loc fyear=`baseline'+(`period'-1)*`n' qui keep Index-Type e0_`fyear' list Place e0_`fyear' if Place=="`place'", clean noobs qui su e0_`fyear' if Place=="`place'" loc surv `r(mean)' restore mata: surv= `surv' } if "`two'" == "" & "`surv'"!="" { *Age-specific survival curve mata: s= L/n //Sx mata: surv= `surv' *Sigma represents the dynamic ratio required to rectangularize the survival * curve. It varies as a function of the future value ex0, informed in `surv'. * Sigma and alfa are optimized to predict a survival curve compatible with * the current age structure of Sx preserve getmata s a mata: st_local("e0", strofreal(T[1], "%4.2f")) qui nl (s=1/(1+(a/(`e0'+{alfa}))^{sigma})), init(alfa 0) //nonlinear LS restore if "`sigma'"== "" { mata: st_local("sig1", strofreal(st_matrix("e(b)")[2], "%4.2f")) // sigma mata: st_local("alf1", strofreal(st_matrix("e(b)")[1], "%4.2f")) // alfa mata: sigma=st_matrix("e(b)")[2]/T[1]*`surv' //future sigma } if "`sigma'" != "" { mata: st_local("sig1", strofreal(`sigma', "%4.2f")) // sigma mata: sigma=`sigma'/(T[1])*`surv' //future sigma preserve getmata s a mata: st_local("e0", strofreal(T[1], "%4.2f")) qui nl (s=1/(1+(a/(`e0'+{alfa}))^`sigma')), init(alfa 0) //nonlinear LS restore mata: st_local("alf1", strofreal(st_matrix("e(b)")[1], "%4.2f")) // alfa } qui mata: alfa=optimize_alfa(sigma, surv) // future alfa providing `surv' mata: Sf=1:/(1:+(a:/(`surv'+alfa)):^sigma) // adapted from Wilson (1994, 17). *Linear Interpolation of age-specific probabilities of survival, which implies *in linear gains in life expectancy over time mata: fsurv=J(rows(M), period+1,.) mata: fsurv[.,period+1]=Sf mata: fsurv[.,1]=s loc periodo= `period'-1 forval x=2/`periodo' { //Interpolation: Brass (1974), Celade (1984, 96) mata: fsurv[.,`x']=(`x'-1)/(period+1-1)*fsurv[.,period+1]+ /// (period+1-`x')/(period+1-1)*fsurv[.,1] } mata: sf=J(rows(fsurv),cols(fsurv),.) //Proj. age-specific probs. of survival forval x=1/`period' { mata: sf[.,`x']=fsurv[.,`x'] } *Graph showing predicted survival scenarios= f(expected_e0) //Current e0: approximated by the area under the survival curve mata: st_local("e0", strofreal(sum(sf[.,1])*n, "%4.2f")) //last expected e0: also approximated by the area under the survival curve mata: st_local("e02", strofreal(sum(sf[.,cols(sf)])*n, "%4.2f")) mata: st_local("sig2", strofreal(sigma, "%4.2f")) //future sigma mata: st_local("alf2", strofreal(alfa, "%4.2f")) // future alfa preserve forval x=1/`period' { //Generates variables of projected sx mata: st_store(.,st_addvar("float","s`x'"),sf[.,`x']) } qui des //Graphs age structure of survival probabilities loc pn=`r(k)' qui ds tokenize "`r(varlist)'" loc last_p =`period'+1 line `5'-``pn'' `1', lwidth(vthick) /// || line ``pn'' `1', lp(dash_dot) lwidth(vthick) /// , ti() graphregion(fcolor(white)) /// ytitle(Age-specific Prob. of Survival (s{sub:x})) /// leg(on order(1 "{bf:Current period}" /// "(e{sub:0}{sup:}= `e0', {&alpha}= `alf1', {&sigma}= `sig1')" `last_p' /// "{bf:Last period}" "(e{sub:0}{sup:f}= `e02', {&alpha}{sup:f}= `alf2', {&sigma}{sup:f}= `sig2')") /// region(lc(%0)) pos(6) col(2) all) name(prob_surv, replace) /// note({it:Note}: Life expectancy at birth (e{sub:0}{sup:}) estimated /// as the area under the survival curve (S{sub:x})., span) `gropts' restore *Execute forward projections with varying survival (i.e. fixed m) forval z=1/`periodo' { //projections mata: M= subd(sf[.,`z'],sf[.,`z']*n,m) //places surv. ratios in off diagonal mata: fp[.,`z'+1]= M*fp[.,`z'] //assumes that only survival is changing } } *Fertility and Survival changing at the same time (i.e., varying m) if "`two'"=="" & ("`fert'" != "" & "`surv'"!="") { forval y=1/`periodo' { //projections mata: M= subd(sf[.,`y'],sf[.,`y']*n,f_asfr[`y']/n/(1+`srb')) if "`male'"!="" { mata: M= subd(sf[.,`y'],sf[.,`y']*n,f_asfr[`y']/n*(`srb'/(1+`srb'))) } mata: M[1,.]=fF[`y'+1,.] mata: fp[.,`y'+1]= M*fp[.,`y'] // assumes varying fertility and survival } } *********************************** *TWO-SEXES simultaneous projection* *********************************** *FERTILITY* *********** if "`two'" != "" & ("`fert'"!="" | "`baseline'"!="0") { *Future net female ASFR rates in rows of fF mata: fF=J(period+1,cols(M),.) mata: fF[1,.]=M[1,.] // first row of projection matrix F^f (eq. 7) loc periodo= `period'-1 *Future net male ASFR rates in rows of fFm mata: fFm=J(period+1,cols(M),.) mata: fFm[1,.]=M[length(p)/2+1,.] // first row of proj. matrix F^m (eq. 7) *Future ASFR rates in rows of fasfr_t mata: fasfr_t=J(length(f)/2,period+1,.) mata: fasfr_t[.,1]=f[1..length(f)/2,.] // ASFRs if "`baseline'"=="0" & "`fert'" != "" { mata: r_fert= (`fert'/(colsum(f)*n))^(1/period)-1 //compound growth rate forval x=2/`period' { // future net female ASFR levels, same age pattern mata: fF[`x',.]=fF[`x'-1,.]+fF[`x'-1,.]*r_fert } forval x=2/`period' { // future net male ASFR, same age pattern mata: fFm[`x',.]=fFm[`x'-1,.]+fFm[`x'-1,.]*r_fert } } if "`baseline'"!="0" { if "`place'"!= "" { preserve use "wpp2024_median_fert.dta", replace loc fyear=`baseline'+(`period'-1)*`n' l Place Year TFR if Place== "`place'" & Year==`fyear', clean noobs qui putmata asfr_std=(asfr_10-asfr_50) if Place== "`place'" & /// Year==`fyear', replace restore mata: fasfr=J(1,rows(a),0) mata: fasfr[3..11]=asfr_std/1000*n //final ASFR values } if "`fert'"!="" { preserve use "wpp2024_median_fert.dta", replace mata: st_local("n", strofreal(n)) loc fyear=`baseline'+(`period'-1)*`n' qui drop if Year!=`fyear' qui gen Abs_diff= abs(`fert'-TFR) sort Abs_diff l Place Year TFR Abs_diff in 1/5, clean qui gen asfr_std=1 in 1 // choosen pattern qui putmata asfr_std=(asfr_10-asfr_50) if asfr_std==1, replace restore mata: asfr_std=asfr_std/1000*n mata: asfr_std=asfr_std:/rowsum(asfr_std) //Shares of future TFR mata: fasfr=J(1,rows(a),0) mata: fasfr[3..11]=asfr_std*`fert' //final ASFR values } mata: r_fert= (fasfr':/(f*n)):^(1/period):-1 forval x=2/`period' { //future female ASFR levels, borrowed pattern mata: fF[`x',.]=editmissing(fF[`x'-1,.]+fF[`x'-1,.]:*r_fert',0) } forval x=2/`period' { //future male ASFR levels, borrowed pattern mata: fFm[`x',.]=editmissing(fFm[`x'-1,.]+fFm[`x'-1,.]:*r_fert',0) } forval x=2/`period' { //future female ASFR levels, borrowed pattern mata: fasfr_t[.,`x']= editmissing(fasfr_t[.,`x'-1]+fasfr_t[.,`x'-1]:* /// r_fert[1..length(f)/2],0) } } if "`baseline'"=="0" & "`fert'" != "" { forval x=2/`period' { // future net female ASFR levels, same age pattern mata: fasfr_t[.,`x']=fasfr_t[.,`x'-1]+fasfr_t[.,`x'-1]*r_fert } } *Graph of future net female/male ASFRs mata: st_local("tfr", strofreal(colsum(f)*n, "%4.2f")) //current/first tfr mata: st_local("tfr2", strofreal(colsum(fasfr_t[.,cols(fasfr_t)])*n,"%4.2f")) //last tfr mata:st_local("fc_rate", strofreal(mean(r_fert)*100, "%4.2f")) //speed of change mata:st_local("interval", strofreal(n, "%4.0f")) //length of age group preserve qui des loc size=`r(N)'/2 qui keep in 1/`size' forval x=1/`period' { //Generates variables of predicted ASFRs mata: st_store(.,st_addvar("float","fF`x'"), fasfr_t[.,`x']) } qui des //Graphs age structure of age-specific fertility rates loc pn=`r(k)' qui ds tokenize "`r(varlist)'" qui keep if `1'<=50 & `1'>=10 // restricts graph to reproductive ages loc last_p =`period'+1 line `5'-``pn'' `1', lwidth(vthick) /// || line ``pn'' `1', lp(dash_dot) lwidth(vthick) /// , graphregion(fcolor(white)) ytitle(ASFR) ti(Predicted Trajectory of Age /// Specific Fertility Rates) leg(on order(1 "Current" "period (TFR= `tfr')" /// `last_p' "Last" "period (TFR= `tfr2')") region(lc(%0)) pos(6) col(2) /// all) name(asfr, replace) note({it:Note}: Convergence speed corresponds /// to a `fc_rate'% change in TFR per `interval'-year period., span) `gropts' restore mata: fF_both= (select(a,fF'[.,1]:>0),J(rows(select(fF', fF'[.,1]:>0)),1,0), /// select(fF',fF'[.,1]:>0))\(select(a,fF'[.,1]:>0), /// J(rows(select(fFm'[1..rows(fFm')/2,.], fFm'[1..rows(fFm')/2,1]:>0)),1,1), /// select(fFm'[1..rows(fFm')/2,.], fFm'[1..rows(fFm')/2,1]:>0)) preserve drop * mata: st_local("obs", strofreal(rows(fF_both), "%4.0f")) qui set obs `obs' loc last_p1 = `period'+1 loc last_p =`period'+2 forval x=1/`last_p' { //Gen vars. of predicted female/male ASFRs mata: st_store(.,st_addvar("float","m`x'"),fF_both[.,`x']) } lab var m1 "Lower limit of the age group" lab define sex 0 "Net female ASFRs (f{sub:x})" /// 1 "Net male ASFRs (f{sub:x}{sup:m})" lab values m2 sex qui des loc pn=`r(k)' qui ds tokenize "`r(varlist)'" line `3'-``pn'' `1', by(m2, ti() /// note({it:Note}: Convergence speed: `fc_rate'% average change /// in TFR per `interval'-year period., span)) lwidth(vthick) /// || line ``pn'' `1', by(m2) lp(dash_dot) lwidth(vthick) /// , graphregion(fcolor(white)) yti("Average number of female/male births" /// "born to women of reproductive age") /// leg(off order(1 "{bf:Current period}" "(TFR= `tfr')" /// `last_p1' "{bf:Last period}" "(TFR= `tfr2')") /// region(lc(%0)) pos(6) col(2) all) name(asfr_both, replace) `gropts' restore } *Execute forward projections with varying net female and male ASFRs if "`two'"!="" & (("`place'"!="" & "`surv'"=="") | "`fert'" != "") { forval x=2/`period' { //projections mata: M[1,.]= fF[`x',.] mata: M[length(p)/2+1,.]=fFm[`x',.] mata: fp[.,`x']= M*fp[.,`x'-1] // assumes that only TFR is changing } } ********** *SURVIVAL* ********** *Gets final life expectancy from the World Population Prospects (WPP) file if "`two'"!= "" & "`surv'"!="" & "`surv'"!="." & "`baseline'"!="0" /// & "`place'"=="" { tokenize `surv' preserve use "wpp2024_median_e0F.dta", replace loc fyear=`baseline'+(`period'-1)*`n' qui keep Index-Type e0_`fyear' qui gen Abs_diff= abs(e0_`fyear'-`1') sort Abs_diff rename e0_`fyear' Female_e0_`fyear' list Place Female_e0_`fyear' in 1/5, clean ab(14) use "wpp2024_median_e0M.dta", replace loc fyear=`baseline'+(`period'-1)*`n' qui keep Index-Type e0_`fyear' qui gen Abs_diff= abs(e0_`fyear'-`2') sort Abs_diff rename e0_`fyear' Male_e0_`fyear' list Place Male_e0_`fyear' in 1/5, clean ab(12) restore } if "`two'"!= "" & "`surv'"==". ." & "`baseline'"!="0" & "`place'"!="" { preserve use "wpp2024_median_e0F.dta", replace loc fyear=`baseline'+(`period'-1)*`n' qui keep Index-Type e0_`fyear' rename e0_`fyear' Female_e0_`fyear' list Place Female_e0_`fyear' if Place=="`place'", clean noo ab(14) qui su Female_e0_`fyear' if Place=="`place'" loc surv_f `r(mean)' use "wpp2024_median_e0M.dta", replace loc fyear=`baseline'+(`period'-1)*`n' qui keep Index-Type e0_`fyear' rename e0_`fyear' Male_e0_`fyear' list Place Male_e0_`fyear' if Place=="`place'", clean noo ab(14) qui su Male_e0_`fyear' if Place=="`place'" loc surv_m `r(mean)' restore loc surv "`surv_f' `surv_m'" } if "`two'" != "" & "`surv'" != "" { mata: s= L/n //Sx *Sex-specific sigma, alfa and survival curves tokenize `surv' *Females qui des loc fsize =`r(N)'/2 mata: s_f=s[1..`r(N)'/2] preserve getmata s a mata: st_local("e0_f", strofreal(T[1], "%4.2f")) qui nl (s=1/(1+(a/(`e0_f'+{alfa}))^{sigma})) in f/`fsize', init(alfa 0) restore if "`sigma'"== "" { mata: st_local("alf1_f", strofreal(st_matrix("e(b)")[1], "%4.2f")) // alfa mata: st_local("sig1_f", strofreal(st_matrix("e(b)")[2], "%4.2f")) // sigma mata: sigma_f=st_matrix("e(b)")[2]/(T[1])*`1' //future sigma qui mata: alfa_f=optimize_alfat(sigma_f, `1') //future fem. alfa mata: Sf_f=1:/(1:+(a[1..length(a)/2]:/(`1'+alfa_f)):^sigma_f) //fem. surv. curve } if "`sigma'" != "" { loc surv_f= `1' loc surv_m= `2' tokenize `sigma' mata: st_local("sig1_f", strofreal(`1', "%4.2f")) // sigma mata: sigma_f=`1'/(T[1])*`surv_f' //future sigma preserve getmata s a mata: st_local("e0_f", strofreal(T[1], "%4.2f")) qui nl (s=1/(1+(a/(`e0_f'+{alfa}))^`1')) in f/`fsize', init(alfa 0) restore mata: st_local("alf1_f", strofreal(st_matrix("e(b)")[1], "%4.2f")) //alfa qui mata: alfa_f=optimize_alfat(sigma_f, `surv_f') //future fem. alfa mata: Sf_f=1:/(1:+(a[1..length(a)/2]:/(`surv_f'+alfa_f)):^sigma_f) //fem. surv. curve } *Males qui des mata: s_m=s[`r(N)'/2+1..`r(N)'] preserve getmata s a mata: st_local("e0_m", strofreal(T[length(T)/2+1], "%4.2f")) qui des loc msize =`r(N)'/2+1 qui nl (s=1/(1+(a/(`e0_m'+{alfa}))^{sigma})) in `msize'/l, init(alfa 0) //nonlinear LS restore if "`sigma'"== "" { mata: st_local("alf1_m", strofreal(st_matrix("e(b)")[1], "%4.2f")) // alfa mata: st_local("sig1_m", strofreal(st_matrix("e(b)")[2], "%4.2f")) // sigma mata: sigma_m=st_matrix("e(b)")[2]/(T[length(T)/2+1])*`2' //future sigma qui mata: alfa_m=optimize_alfat(sigma_m, `2') //future male alfa mata: Sf_m=1:/(1:+(a[1..length(a)/2]:/(`2'+alfa_m)):^sigma_m) //male surv. curve } if "`sigma'" != "" { mata: st_local("sig1_m", strofreal(`2', "%4.2f")) // sigma mata: sigma_m=`2'/(T[length(T)/2+1])*`surv_m' //future sigma preserve getmata s a mata: st_local("e0_m", strofreal(T[length(T)/2+1], "%4.2f")) qui nl (s=1/(1+(a/(`e0_m'+{alfa}))^`2')) in `msize'/l, init(alfa 0) restore mata: st_local("alf1_m", strofreal(st_matrix("e(b)")[1], "%4.2f")) //alfa qui mata: alfa_m=optimize_alfat(sigma_m, `surv_m') //future male alfa mata: Sf_m=1:/(1:+(a[1..length(a)/2]:/(`surv_m'+alfa_m)):^sigma_m) //male surv. curve } *Interpolation of survival curves *Females mata: fsurv_f=J(rows(M)/2, period+1,.) mata: fsurv_f[.,period+1]=Sf_f mata: fsurv_f[.,1]=s_f loc periodo= `period'-1 forval x=2/`periodo' { // Brass (1974), Celade (1984, 96) mata: fsurv_f[.,`x']=(`x'-1)/(period+1-1)*fsurv_f[.,period+1]+ /// (period+1-`x')/(period+1-1)*fsurv_f[.,1] } mata: sf_f=J(rows(fsurv_f),cols(fsurv_f),.) //Proj. age-specific probs. of surv. forval x=1/`period' { mata: sf_f[.,`x']=fsurv_f[.,`x'] } *Males mata: fsurv_m=J(rows(M)/2, period+1,.) mata: fsurv_m[.,period+1]=Sf_m mata: fsurv_m[.,1]=s_m forval x=2/`periodo' { // Brass (1974), Celade (1984, 96) mata: fsurv_m[.,`x']=(`x'-1)/(period+1-1)*fsurv_m[.,period+1]+ /// (period+1-`x')/(period+1-1)*fsurv_m[.,1] } mata: sf_m=J(rows(fsurv_m),cols(fsurv_m),.) //Proj. age-specific probs. of surv. forval x=1/`period' { mata: sf_m[.,`x']=fsurv_m[.,`x'] } *Execute simultaneous two-sex projection only with varying survival qui des forval z=1/`periodo' { //projections mata: M[1..`r(N)'/2,1..`r(N)'/2]= subd(sf_f[.,`z'],sf_f[.,`z']*n, /// m[1..`r(N)'/2]) //M^f mata: M[`r(N)'/2+1..`r(N)',`r(N)'/2+1..`r(N)']= subd(sf_m[.,`z'], /// sf_f[.,`z']*n,mm[1..`r(N)'/2]) //M^m mata: M[`r(N)'/2+1,1..`r(N)'/2]= M[`r(N)'/2+1,`r(N)'/2+1..`r(N)'] //F^m mata: M[`r(N)'/2+1,`r(N)'/2+1..`r(N)']= J(1,`r(N)'/2,0) //S^m mata: fp[.,`z'+1]= M*fp[.,`z'] //assumes that only survival is changing } *Graph of predicted survival scenarios, for females and males *FEMALES //Current female e0: area under the survival curve mata: st_local("e0_f", strofreal(sum(sf_f[.,1])*n, "%4.2f")) //last expected female e0 mata:st_local("e02_f",strofreal(sum(sf_f[.,cols(sf_f)])*n,"%4.2f")) mata: st_local("sig2_f", strofreal(sigma_f, "%4.2f")) //future fem. sigma mata: st_local("alf2_f", strofreal(alfa_f, "%4.2f")) //future fem. alfa *MALES //Current male e0: area under the survival curve mata: st_local("e0_m", strofreal(sum(sf_m[.,1])*n, "%4.2f")) //last expected female e0 mata:st_local("e02_m",strofreal(sum(sf_m[.,cols(sf_m)])*n,"%4.2f")) mata: st_local("sig2_m", strofreal(sigma_m, "%4.2f")) //future male sigma mata: st_local("alf2_m", strofreal(alfa_m, "%4.2f")) //future fem. alfa mata: sf_both=J(rows(sf_f),1,0),sf_f\J(rows(sf_m),1,1),sf_m preserve loc last_p =`period'+1 forval x=1/`last_p' { //Generates variables of projected female and male sx mata: st_store(.,st_addvar("float","sf`x'"),sf_both[.,`x']) } label define sex 0 "Female" 1 "Male" label values sf1 sex qui des //Graphs age structure of survival probabilities loc pn=`r(k)' qui ds tokenize "`r(varlist)'" line `6'-``pn'' `1', by(sf1, ti() /// note({it:Note}: Life expectancy at birth (e{sub:0}{sup:}) estimated as /// the area under the survival curve (S{sub:x})., span)) lwidth(vthick) /// || line ``pn'' `1', by(sf1) lp(dash_dot) lwidth(vthick) /// , graphregion(fcolor(white)) ytitle(Age-specific Prob. of Survival (s{sub:x})) /// leg(off order(1 "{bf:Current period}" /// "Females: e{sub:0}{sup:}= `e0_f'" /// "({&alpha}= `alf1_f', {&sigma}= `sig1_f')" /// "Males: e{sub:0}{sup:}= `e0_m'" /// "({&alpha}= `alf1_m', {&sigma}= `sig1_m')" /// `last_p' "{bf:Last period}" /// "Females: e{sub:0}{sup:f}= `e02_f'" /// "({&alpha}{sup:f}= `alf2_f', {&sigma}{sup:f}= `sig2_f')" /// "Males: e{sub:0}{sup:f}= `e02_m'" /// "({&alpha}{sup:f}= `alf2_m', {&sigma}{sup:f}= `sig2_m')") /// region(lc(%0)) pos(6) col(2) all) name(pr_surv_both, replace) `gropts' restore } *Fertility and Survival changing at the same time, for both sexes if "`two'" != "" & ("`fert'" != "" & "`surv'"!= "") { qui des forval z=1/`periodo' { //both-sexes simultaneous projections mata: M[1..`r(N)'/2,1..`r(N)'/2]= subd(sf_f[.,`z'],sf_f[.,`z']*n, /// fasfr_t[.,`z']/(1+`srb')) //M^f mata: M[`r(N)'/2+1..`r(N)',`r(N)'/2+1..`r(N)']= subd(sf_m[.,`z'], /// sf_f[.,`z']*n,fasfr_t[.,`z']/(1+1/`srb')) //M^m mata: M[1,.]= fF[`z'+1,.] mata: M[length(p)/2+1,.]=fFm[`z'+1,.] mata: fp[.,`z'+1]= M*fp[.,`z'] // assumes varying fertility and survival } } ******************************* *GRAPHS: projected populations* ******************************* if "`two'" == "" & "`multistate'" == "" { preserve forval x=2/`period' { // generates variables of projected pops. mata: st_store(.,st_addvar("float","fp`x'"),fp[.,`x']) } qui des //Graphs size of projected populations loc pn=`r(k)' qui ds tokenize "`r(varlist)'" line `5'-``pn'' `1', lwidth(vthick) /// || line ``pn'' `1', lp(dash_dot) lwidth(vthick) /// , graphregion(fcolor(white)) ytitle(Size of projected population) /// legend(on order(1 "First projection" `period' "Last projection") /// region(lc(%0)) pos(6) col(2) all) name(proj, replace) `gropts' restore mata: fpt=fp\colsum(fp) mata: st_matrix("fp_x", round(fpt)[.,2..`period']) preserve gen str_age=string(`1') gen str_age_1=string(`1'[_n+1]-1) gen row_label=str_age + "-" + str_age_1 qui replace row_label=str_age[_N]+"+" in l forval i=1/`=_N' { loc row_lab "`row_lab' `=row_label[`i']'" } restore if "`baseline'"!="0" { preserve drop _all loc periodo= `period'-1 qui set obs `periodo' qui gen col_label= `baseline'+`n' in 1 forval c=2/`periodo' { qui replace col_label=col_label[_n-1]+`n' in `c' } forval c= 1/`=_N' { loc col_lab "`col_lab' `=col_label[`c']'" } restore } matrix rownames fp_x= `row_lab' Total matrix colnames fp_x= `col_lab' matlist fp_x, tit("Projected population in each age group") /// format(%10.0f) row(Age group) aligncolnames(r) tw(9) lin(rowt) return mat proj = fp_x // Returns projected pop. as a system matrix } if "`two'" != "" { preserve gen count=_n qui su gen pyra=cond(count<=`r(N)'/2,1,-1) // vector 1,-1 to generate pyramid forval x=2/`period' { mata: st_store(.,st_addvar("float","fp`x'"),fp[.,`x']) qui replace fp`x'= pyra*fp`x'/1000 } drop count pyra qui des //Graphs size of projected populations loc pn=`r(k)' loc size = `r(N)'/2 loc size1 = `r(N)'/2+1 qui ds tokenize "`r(varlist)'" line `5'-``pn'' `1' in f/`size', lc(black) lwidth(vthick) lp(solid) /// || line ``pn'' `1' in f/`size', lc(gray) lwidth(vthick) lp(dash_dot) /// || line `5'-``pn'' `1' in `size1'/l, lc(black) lw(vthick) lp(solid) /// || line ``pn'' `1' in `size1'/l, lc(gray) lw(vthick) lp(dash_dot) /// || line ``pn'' `1' in `size1'/l, yscale(ax(2)) ylabel(none,axis(2)) /// yti("Female Male", axis(2) orient(rvertical)) /// yaxis(2) lc(blue%15) lw(none) yline(0) /// , xlabel(#`size', angle(rvertical) value) xscale(extend nolin) /// ylabel(, angle(rvertical)) graphregion(fcolor(white)) /// ytitle(Size of projected population (per 1000), orient(rvertical)) /// legend(on order(1 "First projections" `period' "Last projections") /// region(lc(%0)) pos(6) col(2) all) name(projtwo, replace) `gropts' restore mata: ffp= fp[1..length(p)/2,.] //female projected population mata: mfp= fp[(length(p)/2)+1..length(p),.] //male projected population mata: ffpt=ffp\colsum(ffp) // female pop. w/ totals mata: mfpt=mfp\colsum(mfp) // male pop. w/ totals *Females mata: st_matrix("ffp_x", round(ffpt)[.,2..`period']) qui levelsof `1', local(rows) preserve gen str_age=string(`1') gen str_age_1=string(`1'[_n+1]-1) gen row_label=str_age + "-" + str_age_1 qui replace row_label=str_age[_N]+"+" in l forval i=`size1'/`=_N' { loc row_lab "`row_lab' `=row_label[`i']'" } restore if "`baseline'"!="0" { preserve drop _all loc periodo= `period'-1 qui set obs `periodo' qui gen col_label= `baseline'+`n' in 1 forval c=2/`periodo' { qui replace col_label=col_label[_n-1]+`n' in `c' } forval c= 1/`=_N' { loc col_lab "`col_lab' `=col_label[`c']'" } restore } mata: st_local("n", strofreal(n)) matrix rownames ffp_x= `row_lab' Total matrix colnames ffp_x= `col_lab' matlist ffp_x, tit("Projected female population in each age group") /// format(%10.0f) row(Age group) aligncolnames(r) tw(9) lin(rowt) return mat fproj = ffp_x // Returns proj. pop. as a system matrix *Males mata: st_matrix("mfp_x", round(mfpt)[.,2..`period']) *qui levelsof `1', local(rows) matrix rownames mfp_x= `row_lab' Total matrix colnames mfp_x= `col_lab' matlist mfp_x, tit("Projected male population in each age group") /// format(%10.0f) row(Age group) aligncolnames(r) tw(9) lin(rowt) return mat mproj = mfp_x // Returns proj. pop. as a system matrix } if "`multistate'" != "" { preserve qui ds tokenize "`r(varlist)'" qui des keep `1' ``r(k)'' qui su loc ageg=round(`r(N)'/`r(max)'/2) forval x=2/`period' { mata: st_store(.,st_addvar("float","fp`x'"),fp[.,`x']) qui replace fp`x'= fp`x'/1000 } qui des //Graphs size of projected pops. by state loc pn=`r(k)' loc last=`pn'-1 qui ds tokenize "`r(varlist)'" line `3'-``pn'' `1', lw(vthick) /// || line ``pn'' `1', lw(vthick) lp(dash_dot) /// , by(`2', style(stata7) noedgelabel) legend(region(lc(%0)) pos(6) /// col(2) all order(1 "First" "projections" `last' "Last" "projections")) /// ytitle(Size of projected population (per 1000)) /// xlabel(#`ageg') name(multi, replace) `gropts' restore qui ds tokenize "`r(varlist)'" *qui levelsof `1', local(rows) preserve qui su gen str_age=string(age) gen str_age_1=string(age[_n+1]-1) gen row_label=str_age + "-" + str_age_1 qui replace row_label=str_age[_N]+"+" in l loc init_last=`r(N)'-`r(N)'/`r(max)'+1 forval i=`init_last'/`=_N' { loc row_lab "`row_lab' `=row_label[`i']'" } restore qui su ``r(k)'' *mata: st_local("n", strofreal(n)) forval x=1/`r(max)' { mata: st_matrix("fps`x'",round(panelsubmatrix(fp,`x',info)\ /// colsum(panelsubmatrix(fp,`x',info)))[.,2..`period']) matrix rownames fps`x'= `row_lab' Total matlist fps`x', tit("Projected population by age group in state `x'") /// format(%10.0f) row(Age group) aligncolnames(c) tw(9) lin(rowt) return mat mproj`x'= fps`x' } } ***************** *STABLE ANALYSIS* ***************** if "`stable'" == "stable" { mata: values = J(0,0,.) mata: vectors = J(0,0,.) mata: eigensystem(M, vectors, values) //Stable analysis using eigenvalues if "`two'" == "" & "`multistate'"=="" { mata: r0= log(values[1])/n //Intrinsic yearly growth rate mata: stable0= Re(vectors[,1]/sum(vectors[,1])) //Stable age structure mata: r1= newton(nrr,a,L,m)[.,1] //Newton's approximation mata: stable1= 1/sum(exp(-r1*a):*L)*exp(-r1*a):*L mata: no= no(r0,M) //projection periods to stability mata: st_local("no",strofreal(no)) loc no=`no'+1 mata: fps=J(st_nobs(),`no',0) // projected population to stability mata: fps[.,1] = p mata: cs=J(st_nobs(),`no',0) mata: cs[.,1] = p/colsum(p) forval x=2/`no' { mata: fps[.,`x']= M*fps[.,`x'-1] // population projections mata: cs[.,`x']= fps[.,`x']/colsum(fps[.,`x']) //age structure of proj pops. } mata: stable2= cs[.,`no'] mata: statio= L/T[1] mata: ytos= no*n // approximate # of years to stability, given set tolerance mata: stables= cs[.,1], stable0, stable1, stable2, statio mata: st_matrix("stables",stables*100) mat colnames stables= Current Eigen Newton Projected* Stationary mat rownames stables=`rows' mata: st_local("n", strofreal(n)) matlist stables, tit("Age structure of current and stable-equivalent" /// "populations: percent between ages x and x+`n'") /// format(%10.4f) row(Age x) aligncolnames(r) tw(5) border(bottom) mata: st_local("x", strofreal(ytos)) loc note= "*Convergence to stability achieved after about `x' years." di "`note'" return mat stable = stables //Returns pop. struct. as a sys. matrix preserve forval x=1/5 { // generates variables of stable age structures mata: st_store(.,st_addvar("float","stable`x'"),stables[.,`x']*100) } qui des //Graphs size of projected populations loc var=`r(k)' qui ds tokenize "`r(varlist)'" line `5'-``var'' `1', lc(black%75 gs12%65 gs8%75 gs4%85 gs0%95) /// lwidth(vvthick vvthick vthick thick medthick) lpat(solid solid dash dot /// solid) , graphregion(fcolor(white)) ytitle(Age structure (%)) /// legend(on order(1 "Current" 2 "Stable (Eigen)" 3 "Stable (Newton)" /// 4 "Stable (Projected)" 5 "Stable (Stationary)") region(lc(%0)) /// pos(6) col(2) all) name(stable, replace) `gropts' restore } if "`two'" != "" { mata: mr0= log(values[1])/n // intrinsic male rate mata: fr0= log(values[2])/n // intrinsic female rate mata: stable0= J(length(p),1,.) // females on top and males at the bottom mata: stable0[1..(length(p)/2)]= Re(vectors[1..length(p)/2,1]/ /// sum(vectors[1..length(p)/2,1])) mata: stable0[(length(p)/2)+1..length(p)]= Re(vectors[(length(p)/2)+ /// 1..length(p),1]/sum(vectors[(length(p)/2)+1..length(p),1])) mata: fps= J(st_nobs(),50,0) // projected pop. to stability (50 periods) mata: fps[.,1] = p mata: cs= J(st_nobs(),50,0) // females on top and males at the bottom mata: cs[1..length(p)/2,1]= p[1..length(p)/2]/colsum(p[1..length(p)/2]) mata: cs[(length(p)/2)+1..length(p),1]=p[(length(p)/2)+1..length(p)]/ /// colsum(p[(length(p)/2)+1..length(p)]) forval x=2/50 { //age structures of projected populations mata: fps[.,`x']=M*fps[.,`x'-1] // population projections mata: cs[1..length(p)/2,`x']=fps[1..length(p)/2,`x']/ /// //female colsum(fps[1..length(p)/2,`x']) mata: cs[(length(p)/2)+1..length(p),`x']=fps[(length(p)/2)+ /// //male 1..length(p),`x']/colsum(fps[(length(p)/2)+1..length(p),`x']) } mata: stable2=cs[.,50] mata: statio=J(length(L),1,0) mata: statio[1..length(L)/2]=L[1..length(L)/2]/T[1] //females mata: statio[(length(L)/2)+1..length(L)]=L[(length(L)/2)+1..length(L)]/ /// T[(length(L)/2)+1] //males mata: stables= cs[.,1], stable0, stable2, statio *Female stable-equivalent mata: st_matrix("fstables",stables[1..length(p)/2,.]*100) mat colnames fstables= Current Eigen Projected* Stationary mat rownames fstables=`rows' mata: st_local("n", strofreal(n)) matlist fstables, tit("Female age structure of current and" /// "stable-equivalent populations: percent between ages x and x+`n'") /// format(%10.4f) row(Age x) aligncolnames(r) tw(5) border(bottom) return mat fstable= fstables *Male stable-equivalent mata: st_matrix("mstables",stables[(length(p)/2)+1..length(p),.]*100) mat colnames mstables= Current Eigen Projected* Stationary mat rownames mstables=`rows' mata: st_local("n", strofreal(n)) matlist mstables, tit("Male age structure of current and" /// "stable-equivalent populations: percent between ages x and x+`n'") /// format(%10.4f) row(Age x) aligncolnames(r) tw(5) border(bottom) mata: st_local("x", strofreal(50*n)) loc note= "*After `x' years." di "`note'" return mat mstable= mstables //Returns pop. structures as a system matrix preserve mata: stables=stables[1..length(p)/2,.]\ /// stables[(length(p)/2)+1..length(p),.]*-1 forval x=1/4 { // generates variables of stable age structures mata: st_store(.,st_addvar("float","stable`x'"),stables[.,`x']*100) } qui des //Graphs size of projected populations loc var=`r(k)' qui ds tokenize "`r(varlist)'" qui su loc size= `r(N)'/2 loc size1=`r(N)'/2+1 line `5'-``var'' `1' in 1/`size', /// lc(black%75 gs12%65 gs8%75 gs4%85 gs0%95) /// lwid(vvthick vvthick vthick thick medthick) /// lp(solid solid dash dot solid) /// || line `5'-``var'' `1' in `size1'/`r(N)', /// lc(black%75 gs12%65 gs8%75 gs4%85 gs0%95) /// lwid(vvthick vvthick vthick thick medthick) /// lp(solid solid dash dot solid) /// || line ``var'' `1' in `size1'/`r(N)', yscal(ax(2)) ylabe(none,axis(2)) /// yti("Female Male", axis(2) orient(rvertical)) /// yaxis(2) lc(blue%15) lw(none) yline(0) /// , xlabel(#`size', angle(rvertical) value) xscale(extend nolin) /// , graphregion(fcolor(white)) ylabel(, angle(rvertical)) /// ytitle(Age structure (%), orient(rvertical)) /// leg(on order(1 "Current" 2 "Stable (Eigen)" 3 "Stable (Projected)" /// 4 "Stable (Stationary)") region(lc(%0)) /// pos(6) col(2) all) name(stabletwo, replace) `gropts' restore } if "`multistate'" != "" { mata: r0= log(values[1])/n //intrinsic growth rate qui des *mata: stable0=J(length(p)/max(st_data((1,st_nobs()),`r(k)')),1,.) mata: fps=J(st_nobs(),50,0) //projected pop. to stability (50 periods) mata: fps[.,1]= p forval x=2/50 { //pop. projections for 50 periods mata: fps[.,`x']= M*fps[.,`x'-1] } qui su forval x=1/`r(max)' { mata: stable0`x'=panelsubmatrix(vectors,`x',info)[.,1]/ /// colsum(panelsubmatrix(vectors,`x',info)[.,1]) mata: cs`x'= panelsubmatrix(p,`x',info)/colsum(panelsubmatrix(p,`x',info)) mata: csp`x'=panelsubmatrix(fps[.,50],`x',info)/ /// colsum(panelsubmatrix(fps[.,50],`x',info)) mata: stables`x'=cs`x',Re(stable0`x'),csp`x' mata: st_matrix("stables`x'",stables`x'*100) mat rownames stables`x'= `rows' mat colnames stables`x'= Current Eigen Projected* mata: st_local("n", strofreal(n)) matlist stables`x', tit("Age structure of current and" /// "stable-equivalent populations in state `x': percent between ages x and x+`n'") /// format(%10.4f) row(Age x) aligncolnames(r) tw(5) border(bottom) mata: st_local("z", strofreal(50*n)) loc note= "*After `z' years." di "`note'" return mat mstable`x'= stables`x' } preserve mata: age= st_data((1,st_nobs()),1) qui des mata: state= st_data((1,st_nobs()),`r(k)') clear getmata age state qui su loc ageg=round(`r(N)'/`r(max)'/2) mata: pilems= J(0,cols(stables1),.) forval x=1/`r(max)' { mata: pilems=pilems\stables`x' } forval x=1/3 { mata: st_store(.,st_addvar("float","pilems`x'"),pilems[.,`x']*100) } qui des //Graphs size of projected populations by state loc pn=`r(k)' *loc last=`pn'-1 qui ds tokenize "`r(varlist)'" line `3'-``pn'' `1', lc(black%75 gs12%65 gs8%75) /// lwidth(vthick vthick thick) lp(solid solid dot) /// , by(state, style(stata7) noedgelabel) legend(region(lc(%0)) pos(6) /// col(2) all order(1 "Current" 2 "Stable (Eigen)" 3 "Stable (Projected)")) /// ytitle(Age structure (%), orient(rvertical)) /// xlabel(#`ageg') name(stablemulti, replace) `gropts' restore } } ****************** *SUMMARY MEASURES* ****************** if "`summary'" == "summary" { if "`two'"=="" & "`multistate'"=="" { mata: m1= T[1] //Life expec. at birth, e0= Mean age at death in stationary pop. qui des loc temp= `r(N)'-1 mata: deaths=J(`temp',1,0) forval x=1/`temp' { mata: deaths[`x',.]=fp[`x',1]-fp[`x'+1,2] //Cohort estimates } mata: deaths[`temp',.]= fp[`r(N)'-1,1]+fp[`r(N)',1]-fp[`r(N)',2] mata: m2= sum(range(n,max(st_data(.,1)),n):*deaths)/sum(deaths) //Mean age at death mata: m3= colsum(a:*p)/colsum(p) //Mean age of the population mata: m4=ln(nrr)/newton(nrr, a, L, m)[.,1] //T(Preston et al 2001: 152). /*"(...)the length of time needed for a population to increase by a factor equal to its NRR" (Schoen 1988: 45).*/ mata: m5= sum(a:*(m/nrr):*L) //Mean age of the maternity schedule mata: m6= newton(nrr, a, L, m)[.,2] //Mean age of childbear. in stable pop. mata: m7= colsum(f)*n //Period TFR mata: m8= colsum(m)*n //Gross reproduction rate (GRR) mata: m9= sum (L :* m) //Net reproduction rate (NRR) mata: m10= sum(p:*m)/sum(p) //Crude birth rate (CBR), assuming a fem. pop.(p) mata: m11= 1/sum(exp(-newton(nrr,a,L,m)[.,1]*a):*L) //Intrinsic birth rate (b) mata: m12= m11-newton(nrr, a, L, m)[.,1] //Intrinsic death rate (d) mata: m13= newton(nrr, a, L, m)[.,1] //Intrinsic growth rate (r) mata: values = J(0,0,.) mata: vectors = J(0,0,.) mata: eigensystem(M, vectors, values) //Stable analysis using eigenvalues mata: r0= log(values[1])/n //Intrinsic yearly growth rate mata: stable0= Re(vectors[,1]/sum(vectors[,1])) //Stable age structure mata: m14= colsum(abs((p:/colsum(p))-stable0))*.5 //Keyfitz's delta (1968:47) if "`keyfitz'"== "" { mata: m15= no(r0,M)*n //Years to stability } if "`keyfitz'"!= "" { mata: m15= no2(stable0,M)*n } mata: gr=J(2,4,.) mata: gr(r0,M,gr) *mata: m16= gr[2,1]*n // Years to stability (upper band) mata: m16=(sum(select(p,st_data(.,1):<=`ygual'))+ /// sum(select(p,st_data(.,1):>=65)))/(sum(p)- /// (sum(select(p,st_data(.,1):<=`ygual'))+ /// sum(select(p,st_data(.,1):>=65))))*100 // total age dependency ratio mata: m17= gr[1,1]*n // Years of growth before first decline mata: m18= gr[1,2] // Pop. relative(%) size when decline starts mata: m19= gr[2,2] // Pop. relative(%) size in stability mata: m20= m11*T[1]/sqrt(nrr) // Momentum (Frauenthal 1975) mata: ba=m/nrr:*L mata: w=n*(ba/2+(sum(ba):-runningsum(ba))):/(sum(a:*ba)) mata: m21=sum(w:*(p/colsum(p)):/(L/T[1])) //Momentum (Preston-Guillot 1997) mata: measures=J(21,1,.) //places measures in a matrix forval x=1/21 { mata: measures[`x',.]=m`x' } mata: st_matrix("su",measures) mat colnames su= Value mat rownames su= "Life_expectancy_at_birth(e0)" "Mean_age_at_death" /// "Mean_age_of_the_population" "Mean_length_of_generation" /// "Mean_age_at_maternity" "Mean_age_at_maternity*" /// "Total_fertility_rate(TFR)" "Gross_reproduction_rate(GRR)" /// "Net_reproduction_rate(NRR)" "Crude_birth_rate(CBR)" /// "Intrinsic_birth_rate(b)" "Intrinsic_death_rate(d)" /// "Intrinsic_growth_rate(r)" "Keyfitz's_delta" "Years_to_stability" /// "Total_age_dependency_ratio(%)" "Years_of_positive_growth" /// "Proj./obs._when_decline_starts" "Proj./obs._in_stability" /// "Momentum_(Frauenthal_1975)" "Momentum_(Preston-Guillot_1997)" matlist su, tit("Summary measures for the baseline population") row(Measure) /// aligncolnames(c) underscore border(bottom) /// cspec(& L %32s|%10.4f &) rspec(--&&&&&&&&&&&&&&&&&&&&-) loc note= "*In the stable population." di "`note'" return mat summary = su // Returns measures as a system matrix } if "`two'"!="" { mata: fm1= T[1] //Life expec. at birth mata: mm1= T[(length(L)/2)+1] qui su loc temp= `r(N)'/2-2 *Female deaths and mean age at death mata: f_deaths=J(`temp',1,0) forval x=1/`temp' { mata: f_deaths[`x',.]=fp[`x',1]-fp[`x'+1,2] //Cohort estimates } mata: f_deaths= f_deaths\ fp[`r(N)'/2-1,1]+fp[`r(N)'/2,1]-fp[`r(N)'/2,2] mata: fm2= mean(range(n,max(st_data(.,1)),n),f_deaths) *Male deaths and mean age at death mata: m_deaths=J(`temp',1,0) forval x=1/`temp' { mata: m_deaths[`x',.]=fp[`x'+`r(N)'/2,1]-fp[`x'+`r(N)'/2+1,2] //Cohort estimates } mata: m_deaths= m_deaths\ fp[`r(N)'-1,1]+fp[`r(N)',1]-fp[`r(N)',2] mata: mm2= mean(range(n,max(st_data(.,1)),n),m_deaths) mata: fm3= colsum(a[1..(length(p)/2)]:*p[1..(length(p)/2)])/ /// colsum(p[1..(length(p)/2)]) //Female mean age of the population mata: mm3= colsum(a[(length(p)/2)+1..(length(p))]:* /// Male mean age p[(length(p)/2)+1..(length(p))])/colsum(p[(length(p)/2)+1..(length(p))]) mata: fm4= ln(fnrr)/newton(fnrr, a[1..(length(p)/2)], L[1..(length(p)/2)], /// m[1..(length(p)/2)])[.,1] //female T(Preston et al 2001: 152) mata: mm4=ln(mnrr)/newton(mnrr, a[(length(a)/2)+1..(length(a))], /// L[(length(L)/2)+1..(length(L))], mm[1..(length(p)/2)])[.,1] //T mata: fm5= sum(a[1..(length(p)/2)]:*(m[1..(length(p)/2)]/fnrr):* /// L[1..(length(p)/2)]) //Mean age of the maternity schedule mata: mm5= sum(a[(length(a)/2)+1..(length(a))]:*(mm[1..(length(p)/2)]/mnrr):* /// L[(length(L)/2)+1..(length(L))]) //Mean age of the maternity mata: fm6= newton(fnrr, a[1..(length(a)/2)], L[1..(length(L)/2)], /// m[1..(length(p)/2)])[.,2] //Mean age of childbear. in stable pop. mata: mm6= newton(mnrr, a[(length(a)/2)+1..(length(a))], L[(length(L)/ /// 2)+1..(length(L))], mm[1..(length(p)/2)])[.,2] //Male child's mean age mata: fm7= colsum(f)*n //Period TFR mata: mm7= colsum(f)*n //Period TFR mata: fm8= colsum(m)*n //female Grr(GRR) mata: mm8= colsum(mm)*n //male Grr(GRR) mata: fm9= sum(L[1..(length(L)/2)]:*m[1..(length(p)/2)]) //female NRR mata: mm9= sum(L[(length(L)/2)+1..(length(L))]:*mm[1..(length(p)/2)]) //male NRR mata: fm10= sum(p[1..(length(p)/2)]:*m[1..(length(p)/2)])/ /// sum(p[1..(length(p)/2)]) //CBR, female pop. mata: mm10=sum(p[(length(p)/2)+1..(length(p))]:*mm[1..(length(p)/2)])/ /// sum(p[(length(p)/2)+1..(length(p))]) //CBR, male pop. mata: fm11= 1/sum(exp(-newton(fnrr,a[1..(length(a)/2)],L[1..(length(L)/2)], /// m[1..(length(p)/2)])[.,1]*a[1..(length(a)/2)]):* /// L[1..(length(L)/2)]) //female b mata: mm11= 1/sum(exp(-newton(mnrr,a[(length(a)/2)+1..(length(a))], /// L[(length(L)/2)+1..(length(L))],mm[1..(length(p)/2)])[.,1]* /// a[(length(a)/2)+1..(length(a))]):*L[(length(L)/2)+1..(length(L))]) //male b mata: fm12= fm11-newton(fnrr, a[1..(length(p)/2)], L[1..(length(p)/2)], /// m[1..(length(p)/2)])[.,1] //female (d) mata: mm12= mm11-newton(mnrr, a[(length(a)/2)+1..(length(a))], /// L[(length(L)/2)+1..(length(L))], mm[1..(length(p)/2)])[.,1] //male (d) mata: fm13= newton(fnrr, a[1..(length(p)/2)], L[1..(length(p)/2)], /// m[1..(length(p)/2)])[.,1] //female (r) mata: mm13= newton(mnrr, a[(length(a)/2)+1..(length(a))], /// L[(length(L)/2)+1..(length(L))], mm[1..(length(p)/2)])[.,1] //male (r) mata: values = J(0,0,.) mata: vectors = J(0,0,.) mata: eigensystem(M, vectors, values) //Stable analysis using eigenvalues mata: mr0= log(values[1])/n //male Intrinsic yearly growth rate mata: fr0= log(values[2])/n //female Intrinsic yearly growth rate mata: stable0=J(length(p),1,.) mata: stable0[1..(length(p)/2)]= Re(vectors[1..(length(p)/2),1]/ /// sum(vectors[1..(length(p)/2),1])) //female mata: stable0[(length(p)/2)+1..(length(p))]= Re(vectors[(length(p)/2)+ /// 1..(length(p)),1]/sum(vectors[(length(p)/2)+1..(length(p)),1])) //male mata: fm14= .5*sum(abs(p[1..length(p)/2]:/sum(p[1..length(p)/2])- /// stable0[1..length(p)/2])) // female Keyfitz's delta (1968:47) mata: mm14= sum(abs(p[length(p)/2+1..(length(p))]:/sum(p[length(p)/ /// 2+1..length(p)])-stable0[length(p)/2+1..length(p)]))*.5 // male Keyfitz's D mata: fm15= fm11*T[1]/sqrt(fnrr) //female Momentum (Frauenthal 1975) mata: mm15= mm11*T[(length(L)/2)+1]/sqrt(mnrr) //male Momentum (Frauenthal 1975) mata: fba=m[1..(length(p)/2)]/fnrr:*L[1..(length(p)/2)] mata: mba=mm[1..(length(p)/2)]/mnrr:*L[(length(L)/2)+1..(length(L))] mata: fw=n:*(fba:/2+(sum(fba):-runningsum(fba))):/ /// (sum(a[1..(length(p)/2)]:*(m[1..(length(p)/2)]/fnrr):* /// L[1..(length(p)/2)])) mata: mw=n:*(mba:/2+(sum(mba):-runningsum(mba))):/ /// (sum(a[(length(a)/2)+1..(length(a))]:* /// (mm[1..(length(p)/2)]/mnrr):*L[(length(L)/2)+1..(length(L))])) mata: fm16=sum(fw:*(p[1..(length(p)/2)]/colsum(p[1..(length(p)/2)])):/ /// (L[1..(length(p)/2)]/T[1])) // female Momentum(Preston-Guillot 1997) mata: mm16=sum(mw:*(p[(length(p)/2)+1..(length(p))]/ /// colsum(p[(length(p)/2)+1..(length(p))])):/ /// (L[(length(L)/2)+1..(length(L))]/T[(length(L)/2)+1])) //male Momentum mata: fm17=(sum(select(p[1..length(p)/2], /// st_data(.,1)[1..(length(p)/2)]:<=`ygual'))+ sum(select(p[1..length(p)/2], /// st_data(.,1)[1..(length(p)/2)]:>=65)))/(sum(p[1..length(p)/2])- /// (sum(select(p[1..length(p)/2],st_data(.,1)[1..(length(p)/2)]:<=`ygual'))+ /// sum(select(p[1..length(p)/2], /// st_data(.,1)[1..(length(p)/2)]:>=65))))*100 //female age dep.ratio mata: mm17=(sum(select(p[(length(p)/2)+1..(length(p))], /// st_data(.,1)[(length(p)/2)+1..(length(p))]:<=`ygual'))+ /// sum(select(p[(length(p)/2)+1..(length(p))], /// st_data(.,1)[(length(p)/2)+1..(length(p))]:>=65)))/ /// (sum(p[(length(p)/2)+1..(length(p))])- /// (sum(select(p[(length(p)/2)+1..(length(p))], /// st_data(.,1)[(length(p)/2)+1..(length(p))]:<=`ygual'))+ /// sum(select(p[(length(p)/2)+1..(length(p))], /// st_data(.,1)[(length(p)/2)+1..(length(p))]:>=65))))*100 //male age dep.ratio mata: measures=J(17,2,.) //places measures in a matrix forval x=1/17 { mata: measures[`x',1]=fm`x' //female measures mata: measures[`x',2]=mm`x' //male measures } mata: st_matrix("su",measures) mat colnames su= Female Male mat rownames su= "Life_expectancy_at_birth(e0)" "Mean_age_at_death" /// "Mean_age_of_the_population" "Mean_length_of_generation" /// "Mean_age_at_maternity" "Mean_age_at_maternity*" /// "Total_fertility_rate(TFR)" "Gross_reproduction_rate(GRR)" /// "Net_reproduction_rate(NRR)" "Crude_birth_rate(CBR)" /// "Intrinsic_birth_rate(b)" "Intrinsic_death_rate(d)" /// "Intrinsic_growth_rate(r)" "Keyfitz's_delta" /// "Momentum_(Frauenthal_1975)" "Momentum_(Preston-Guillot_1997)" /// "Total_age_dependency_ratio(%)" matlist su, tit("Summary measures for the baseline populations") row(Measure) /// aligncolnames(c) underscore border(bottom) /// cspec(& L %32s|%10.4f|%10.4f &) rspec(--&&&&&&&&&&&&&&&&-) loc note= "*In the stable population." di "`note'" return mat summary = su // Returns measures as a system matrix } if "`multistate'"!="" { *Life expectancies according to Rogers: T(x)l(x)^-1 (1995, 91) *Calculating T(x) qui su loc n=`r(N)'/`r(max)' forval x=1/`n' { mata: T`n'= L`n' loc index =`n'-`x' loc index2=`index'+1 mata: L0=J(rows(T`n'), cols(T`n'),0) //calculated but ignored mata: T`index'= T`index2'+L`index' } *Multistate life expectancies by STATE OF BIRTH (uncond. or population-based) mata: e0_b= Re(T1*luinv(l1)) mata: e0_b= e0_b\colsum(e0_b) /*Life expectancies (for stayers and for those who were in a given state).*/ /*Calculations use the summation of the conditional probabilties of survival.*/ mata: v4=abs(st_data(.,3):-1) //Prob. of surviving in a given state *mata: e_cond=J(`r(max)',`r(max)',.) *Calculation of ASD preserve //zeros the transition probabilities in the dataset qui des loc last=`r(k)'-1 forval c=5/`last' { loc to `to' `c' } qui ds tokenize `r(varlist)' foreach var of local to { qui replace ``var''=0 } qui des mata: rates_nomob= st_data(.,5..(`r(k)'-1)) mata: q_nomob= st_data(.,3) mata: v1_nomob= st_data(.,`r(k)') mata: info_nomob= panelsetup(v1,1) qui su loc max= `r(max)' // local macro for the number of states forval x=1/`r(max)' { mata pan`x'_nomob= panelsubmatrix(rates_nomob,`x',info_nomob)[.,1..`r(max)'] } clear forval x=1/`max' { getmata (var`x'*)=pan`x'_nomob } foreach var of varlist * { summ `var', meanonly if missing(r(mean)) drop `var' } drop var1* qui des forval x= 1/`r(N)' { mata: N`x'_nomob= N(colshape(st_data(`x',(1..st_nvar())),`max'-1)) //fun. N() mata: q`x'_nomob= diag(colshape(rowshape(q_nomob,`r(N)'),`r(N)')'[`x',.]) mata: P`x'_nomob= (N`x'_nomob-q`x'_nomob)' mata: M`x'_nomob= 2/n*luinv(I(`max')+P`x'_nomob)*(I(`max')-P`x'_nomob) } loc j=`r(N)'-1 restore preserve *Step 2: calculation of survivorship ratios, S(x) mata: l1_nomob=diag(J(`max',1,`l0')) //puts the l0s from mu() in their proper place forval x=2/`r(N)' { loc y= `x'+1 loc z=`x'-1 mata: l`x'_nomob=P`z'_nomob*l`z'_nomob mata: l`y'_nomob= P`x'_nomob*l`x'_nomob mata: d`z'_nomob= l`z'_nomob-l`x'_nomob mata: d`x'_nomob= l`x'_nomob-l`y'_nomob mata: L`z'_nomob= luinv(M`z'_nomob)*d`z'_nomob mata: L`x'_nomob=luinv(M`x'_nomob)*d`x'_nomob } *Calculation of L(x) in the last open-ended age group //gets rid of 0 values to execute log10 mata: L`r(N)'_nomob= l`r(N)'_nomob*luinv(M`r(N)'_nomob) *l`r(N)'_nomob:*diag(log10(diagonal(l`r(N)'_nomob))) qui su loc n=`r(N)'/`r(max)' forval x=1/`n' { mata: T`n'_nomob= L`n'_nomob loc index =`n'-`x' loc index2=`index'+1 mata: L0_nomob=J(rows(T`n'_nomob), cols(T`n'_nomob),0) //calculated but ignored mata: T`index'_nomob= T`index2'_nomob+L`index'_nomob } *Multistate life expectancies by STATE assuming ASD mata: e0_asd= colsum(Re(T1_nomob*luinv(l1_nomob))) restore forval x=1/`r(max)' { mata: m1`x'=e0_asd[.,`x'] *mata: m1`x'= sum(runningprod(panelsubmatrix(v4,`x',info)))*n //e0 in state i /*Expected length of sojourn time in state j(or i) - in columns- given // occupancy of state i - in rows. mata: eij`x'=J(length(panelsubmatrix(v2,`x',info)[.,1]),`r(max)',.) forval s=1/`r(max)' { mata: eij`x'[.,`s']=runningprod(panelsubmatrix(v2,`x',info)[.,`s']) } mata: e_cond[`x',.]=colsum(eij`x')*n */ //Mean ages at transfer from state i /*mata: m2`x'=sum(panelsubmatrix(a,`x',info)[.,1]:* /// ln(abs(panelsubmatrix(v4,`x',info)[.,1]))/-n:* /// panelsubmatrix(p,`x',info)[.,1])/ /// sum(ln(abs(panelsubmatrix(v4,`x',info)[.,1]))/-n:* /// panelsubmatrix(p,`x',info)[.,1]) */ qui su loc temp= `r(N)'/`r(max)' *Deaths and mean age at transfer from state i mata: m2`x'=colsum(panelsubmatrix((1:-sd):*p,`x',info)[2..`temp']:* /// range(n,max(st_data(.,1)),n))/colsum(panelsubmatrix((1:-sd):* /// p,`x',info)[2..`temp']) //Mean ages of the population mata: m3`x'= sum(panelsubmatrix(a,`x',info)[.,1]:* /// panelsubmatrix(p,`x',info)[.,1])/ /// sum(panelsubmatrix(p,`x',info)[.,1]) //Mean age of the pop. //TFRs mata: m4`x'=colsum(panelsubmatrix(v3,`x',info)[.,2])*n //Gross reproduction rates (GRR) mata: m5`x'= colsum(panelsubmatrix(m,`x',info)[.,1])*n //Crude birth rates (CBR) mata: m6`x'= sum(panelsubmatrix(p,`x',info)[.,1]:* /// panelsubmatrix(f,`x',info)[.,1])/ /// sum(panelsubmatrix(p,`x',info)[.,1]) mata: values = J(0,0,.) mata: vectors = J(0,0,.) mata: eigensystem(M, vectors, values) //Stable analysis using eigenvalues mata: m1= log(values[1])/n //Intrinsic yearly growth rate //Stable age structure mata: stable0`x'= panelsubmatrix(Re(vectors[,1]/ /// sum(vectors[,1])),`x',info)[.,1] // Keyfitz's delta (1968: 47) mata: m7`x'= colsum(abs((panelsubmatrix(p,`x',info)[.,1]:/ /// colsum(panelsubmatrix(p,`x',info)[.,1]))-stable0`x'))*.5 // Total age dependency ratio (%) mata: m8`x'= (sum(select(panelsubmatrix(p,`x',info)[.,1], /// panelsubmatrix(st_data(.,1),`x',info)[.,1]:<=`ygual'))+ /// sum(select(panelsubmatrix(p,`x',info)[.,1], /// panelsubmatrix(st_data(.,1),`x',info)[.,1]:>=65))) / /// (sum(select(panelsubmatrix(p,`x',info)[.,1], /// panelsubmatrix(st_data(.,1),`x',info)[.,1]))- /// (sum(select(panelsubmatrix(p,`x',info)[.,1], /// panelsubmatrix(st_data(.,1),`x',info)[.,1]:<=`ygual'))+ /// sum(select(panelsubmatrix(p,`x',info)[.,1], /// panelsubmatrix(st_data(.,1),`x',info)[.,1]:>=65))))*100 mata: m2= no(m1,M)*n // Years to stability mata: gr=J(2,4,.) mata: gr(m1,M,gr) *mata: m3= gr[2,1]*n // Years to stability (upper band) mata: m3= gr[1,1]*n // Years of growth before first decline mata: m4= gr[1,2] // Pop. relative(%) size when decline starts mata: m5= gr[2,2] // Pop. relative(%) size in stability } mata: measures2=J(5,1,.) forval l=1/5 { mata: measures2[`l',1]= Re(m`l') } mata: st_matrix("su2",measures2) mat colnames su2= Value mat rownames su2= "Intrinsic_growth_rate(r)" "Years_to_stability" /// "Years_of_positive_growth" /// "Proj./obs._when_decline_starts" "Proj./obs._in_stability" matlist su2, tit("Summary measures for the total population") row(Measure) /// aligncolnames(c) underscore border(bottom) format(%10.4f) tw(31) return mat summary2 = su2 //Returns measures as a system matrix mata: measures=J(8,`r(max)',.) //places measures in a matrix forval l=1/8 { forval c=1/`r(max)' { mata: measures[`l',`c']= m`l'`c' } } mata: st_matrix("su",measures) forval c=1/`r(max)' { loc State `State' `c' } foreach a of local State { loc colu `colu' State_`a' } mat colnames su= `colu' mat rownames su= "ASD_life_expectancy*" "Mean_age_at_transfer" /// "Mean_age_of_the_population" "Total_fertility_rate(TFR)" /// "Gross_reproduction_rate(GRR)" "Crude_birth_rate(CBR)" /// "Keyfitz's_delta" "Total_age_dependency_ratio(%)" matlist su, tit("Summary measures by state of occupancy") row(Measure) /// aligncolnames(c) underscore border(bottom) format(%10.4f) tw(30) loc notem ="* Associated Single Decrement (ASD) life expectancy assumes that" /// + " death is the only cause of decrement operating to diminish a cohort." di "`notem'" return mat summary = su //Returns measures as a system matrix mata: st_matrix("su3",e0_b) mat colnames su3= `colu' mat rownames su3= `colu' Total matlist su3, tit("Life expectancies at birth by state: sojourn time in state" /// "j (in columns) given occupancy of state i (in rows)") /// row(State-specific e0)aligncolnames(c) underscore border(bottom) /// format(%10.4f) tw(17) lin(rowt) return mat summary3 = su3 } } *Gets rid of intermediate/acessory vectors/matrices in Mata global namespace if "`two'"=="" & "`multistate'"=="" { *mata mata drop L a f fp fpt m n nrr p period if "`stable'" != "" & "`summary'" == "" { mata mata drop r0 r1 stable* statio values vectors ytos cs fps no } if "`summary'" != "" & "`stable'" == "" { mata mata drop ba deaths gr m* r0 stable0 values vectors w } if "`summary'" != "" & "`stable'"!="" { mata mata drop ba deaths gr m* w cs fps r* st* v* ytos no } if "`mig1'" != "" { mata mata drop P nmr op res } if "`fert'" != "" { mata mata drop fF mat_rate r_fert start start2 } if "`surv'" != "" { *mata mata drop Sf fsurv s sf sigma } } if "`two'"!="" { mata mata drop F_m L a f* m* n p period if "`stable'" != "" & "`summary'" == "" { mata mata drop cs s* v* } if "`summary'" != "" & "`stable'" == "" { mata mata drop f_deaths m_deaths stable0 v* } if "`summary'" != "" & "`stable'"!="" { mata mata drop cs s* v* } if "`mig1'" != "" { mata mata drop P* Sm nmr op res } if "`fert'" != "" { mata mata drop r_fert } if "`surv'" != "" { mata mata drop S* } } if "`multistate'"!="" { mata: jM=M mata mata drop M* a* f* info m* n p* s* t* v* d* l* q* L* N* P* S* rat* mata: M=jM mata mata drop jM if "`stable'"!="" & "`summary'" == "" { mata mata drop c* r0 } if "`summary'" != "" & "`stable'" == "" { mata mata drop m* e* gr } if "`summary'" != "" & "`stable'"!="" { mata mata drop c* e* gr r0 } } end //Ends the program **************** *MATA FUNCTIONS* **************** { *Puts the matrix upside down. Taken from Stata Journal(2006)6,n.4,pp.588–589 mata: matrix function flipud(matrix X) { return(rows(X)>1 ? X[rows(X)..1,.] : X) } end *LESLIE MATRIX for one-sex population projection, by G. Rodríguez / 28feb2017 *https://grodri.github.io/demography/project mata: real matrix Leslie(real vector L, real vector m) { n = length(L) M = J(n,n,0) //Lower diagonal has survivorship ratios for (i=1; i < n; i++) { M[i+1,i] = L[i+1]/L[i] } M[n,n-1] = M[n,n]=L[n]/(L[n-1]+L[n]) //First row has net female /male contributions for (i=1; i < n; i++) { if(m[i]==0 & m[i+1]==0) continue M[1,i] = L[1]*(m[i]+m[i+1]*L[i+1]/L[i])/2 } if (m[n] > 0) M[1,n] = L[1]*m[n] return(M) } end *LESLIE MATRIX for males in a two-sex population projection mata: real matrix Lesliem(real vector L, real vector s, real vector m) { n = length(L) M = J(n,n,0) //Lower diagonal has survivorship ratios for (i=1; i < n; i++) { M[i+1,i] = s[i+1]/s[i] } M[n,n-1] = M[n,n]= s[n]/(s[n-1]+s[n]) //First row has net paternity contributions for (i=1; i < n; i++) { if(m[i]==0 & m[i+1]==0) continue M[1,i] = s[1]*(m[i]+m[i+1]*L[i+1]/L[i])/2 } if (m[n] > 0) M[1,n] = s[1]*m[n] return(M) } end *Leslie for MULTISTATE PROJECTION matrices without mobility mata: real matrix Lesliems(real vector sd, prsurv, tft) { n = length(sd) M = J(n,n,0) il= st_data(.,1)[3]-st_data(.,1)[2] // interval length srb=strtoreal(st_local("srb")) // sex ratio at birth //Lower diagonal has survivorship ratios for (i=1; i < n; i++) { M[i+1,i] = sd[i] } M[n,n] = sd[i] //First row has stayers' net fertility contributions for (i=1; i < n; i++) { if(tft[i]==0 & tft[i+1]==0) continue M[1,i] = il/(1+srb)*(tft[i]+tft[i+1]*prsurv[i+1])/2*prsurv[1] } if (tft[n] > 0) M[1,n] = (il/(1+srb))*prsurv[1]*tft[n] return(M) } end * NEWTON'S METHOD to calculate intrinsic growth rate and mean age of * childbearing in the stable population, by G. Rodríguez / 28feb2017 mata: function f (real scalar r, real vector a, real vector L, real vector m) { return(sum(exp(-r:*a):*L:*m)) } function g(r, a, L, m) { return(-sum(a:*exp(-r:*a):*L:*m)) } function newton(nrr, a, L, m) { r = log(nrr)/27 delta = 1 while(delta > 1e-8) { r0 = r f0 = f(r0, a, L, m) g0 = g(r0, a, L, m) r = r0 + (1 - f0)/g0 delta = abs(r - r0) A = -g0/f0 } return(r,A) } end *Function to find the approximate number of years to achieve stability mata: function no(complex scalar r0, real matrix M) { cusp = 1 tolerance= strtoreal(st_local("tolerance")) //tolerance set in syntax c0 = st_data(.,2):/colsum(st_data(.,2)) //Current age distribution no = 0 n=st_data(.,1)[3]-st_data(.,1)[2] while (cusp > tolerance) { c1 = M*c0 r3 = ln(sum(c1)/sum(c0)):/n cusp = abs(r3-r0) no++ c0 = c1 } return(no) } end *Alternative function to find # of years to stability (using Keyfitz' delta) mata: function no2(real vector stable0, real matrix M) { cusp = 1 tolerance= strtoreal(st_local("tolerance")) c0 = st_data(.,2) //Current population no2 = 0 while (cusp > tolerance) { c1 = M*c0:/colsum(M*c0) cusp = .5*colsum(abs(c1-stable0)) no2++ c0 = c1 } return(no2) } end *Function to generate measures m16 to m19 mata: void gr(complex scalar r0,real matrix M, gr) { delta = 1 c0 = st_data(.,2):/colsum(st_data(.,2)) nu=0 first = 1 gr=J(2,4,.) while (delta > 1e-8) { c1 = M*c0 r2 = ln(sum(c1)/sum(c0)):/(st_data(.,1)[3]-st_data(.,1)[2]) delta = abs(r2-r0) nu++ if(r2 < 0 & first) { gr[1,.]=nu, sum(c1), r2, delta first = 0 } c0 = c1 } gr[2,.]=nu, sum(c1), r2, delta return } end *Function to create Leslie matrix for migrants mata: real matrix Leslie2(real vector mprob, real vector mfer) { n=length(mprob) M2=J(n,n,0) //Sub-diagonal has residual net migration probabilities for (i=1; i < n; i++) { M2[i+1,i] = mprob[i+1] } M2[n,n]= 0 //First row has migrants' net maternity contributions for (i=1; i < n; i++) { if(mfer[i]==0 & mfer[i+1]==0) continue M2[1,i] = mfer'[i] } return(M2) } end *Function to calculate the running product of a vector, by Federico Belotti *and Silvio Daidone (net describe runningprod) mata: numeric vector runningprod(numeric vector vec, | real scalar missing) { numeric vector rp real scalar i if (missing == .) tmp = vec else tmp = editmissing(vec, missing) rp = tmp for (i=2; i <= length(vec); i++) { rp[i] = rp[i-1] * tmp[i] } return(rp) } end *Function to calculate the running quotient of a vector mata: numeric vector runningquo(numeric vector vec) { numeric vector rp real scalar i tmp=vec rp=tmp for (i=2; i <= length(vec); i++) { rp[i] = rp[i] / tmp[i-1] } return(rp) } end *Function to place age-specific survivorship ratios in the subdiagonal mata: real matrix subd(real vector s, real vector L, real vector m) { n = length(L) M = J(n,n,0) il= st_data(.,1)[3]-st_data(.,1)[2] // interval length //Lower diagonal has survivorship ratios for (i=1; i < n; i++) { M[i+1,i] = s[i+1]/s[i] } M[n,n-1]=M[n,n]=s[n]/(s[n-1]+s[n]) //First row has net maternity/paternity contributions for (i=1; i < n; i++) { if(m[i]==0 & m[i+1]==0) continue M[1,i] = il*s[1]*(m[i]+m[i+1]*L[i+1]/L[i])/2 } if (m[n] > 0) M[1,n] = il*s[1]*m[n] return(M) } end *Functions to define the parameter sigma. * Sigma shapes the future rectangularization of the survival curve. * Sigma minimizes the mean of two Keyfitz's distances: * 1. the difference btw./ obs. and predicted survival curves (Sx), and * 2. the difference btw./ obs. and predicted probs. of survival (sx). ******************** *for ONE-SEX models* ******************** mata: //Define the objective function y to minimize alfa in the final proj. period void alfa(todo, real scalar x, real scalar n, real vector a, /// real scalar surv, real scalar sigma, real scalar y, /// real vector g, real matrix H) { y=(sum(1:/(1:+(a/(surv+x)):^sigma))*n-surv)^2 } end //Initialize optimization of alfa for one-sex models mata: real scalar optimize_alfa(real scalar sigma, real scalar surv) { S = optimize_init() optimize_init_verbose(S, 0) optimize_init_tracelevel(S, "none") optimize_init_evaluator(S, &alfa()) optimize_init_evaluatortype(S, "d0") optimize_init_params(S, 0) //Initial parameter guesses = 0 optimize_init_technique(S, "nr 10000") n= st_data(.,1)[3]-st_data(.,1)[2] // interval length a= st_data(.,1):+(n/2) //Pass additional arguments optimize_init_argument(S, 1, n) optimize_init_argument(S, 2, a) optimize_init_argument(S, 3, surv) optimize_init_argument(S, 4, sigma) optimize_init_which(S, "min") //Set optimization to minimize return(optimize(S)) //Performs the optimization } end //Initialize optimization of alfa for two-sex models mata: real scalar optimize_alfat(real scalar sigma, real scalar surv) { S = optimize_init() optimize_init_verbose(S, 0) optimize_init_tracelevel(S, "none") optimize_init_evaluator(S, &alfa()) optimize_init_evaluatortype(S, "d0") optimize_init_params(S, 0) //Initial parameter guesses = 0 optimize_init_technique(S, "nr 10000") n= st_data(.,1)[3]-st_data(.,1)[2] // interval length a= st_data(.,1)[1..length(st_data(.,1))/2]:+(n/2) //Pass additional arguments optimize_init_argument(S, 1, n) optimize_init_argument(S, 2, a) optimize_init_argument(S, 3, surv) optimize_init_argument(S, 4, sigma) optimize_init_which(S, "min") //Set optimization to minimize return(optimize(S)) //Performs the optimization } end ***************************************************************************** *Generates matrix of transition PROBABILITIES according to *Schoen (1988: 65, eq. 4.4) mata matrix function N(real matrix b) { x=diag(J(rows(b),1,1)- rowsum(b)) external b for(i=1; i<=rows(x); i++) { for(j=1; j<=cols(x); j++) { if (ij) x[i,j]=b[i,j] } } return(x) } }