*! version 1.0 17march2017 Alicia Pérez-Alonso

capture program drop welflossas
program def welflossas , rclass byable(recall) sortpreserve
version 13 /* This program was written on Stata 14.2 but it was tested that it also runs successfully on version 13 of Stata. */
syntax varlist(min=2 max=3) [aweight fweight iweight] [if] [in] [ , AGgregate ADDStatus CALLFile(string) CALLVar(string) SAVing(string) STats(string) THRincl(real 0) NOGraph Format(string)]
args occp white wage
tempname F wagemv wtot Wj Wjg index rowtot coltot RN  /*
     */ Psi Omega WAD EgapAS Decomp dtilde dtildein FGT pop aux Coord /*
	*/ rslt1 rslt1index rslt1group rslt1value rslt2index rslt2group rslt2value
marksample touse, novarlist

set more off
mata mata clear

if "`format'" == "" loc format "%9.4f"
di ""
di "{hline 100}"
********************************************************************************
********************************************************************************
local occp:  word 1 of `varlist'
local white: word 2 of `varlist'

local stats "`stats'"
local thr `thrincl'
if (`thrincl'<0){
	di as error "Error: threshold must be non-negative."
	exit
	}

quietly: tab `occp' `white' [`weight' `exp'] if `touse', matcell(`F') matcol(`white')
local rr0 = r(r)

qui levelsof `occp' if `touse', local(lo)
qui levelsof `white' if `touse', local(lw)
********************************************************************************
if "`aggregate'" =="" {
	if length(`"`addstatus'"')!= 0 {
		di as error "Error: this option is only allowed for aggregated data."
		exit
	}

	if "`stats'"=="" local stats "mean"
	if "`stats'"=="median" & "`weight'"=="iweight"{
		di as error "Error: iweights not allowed for the median."
		exit
	}

	local wage:  word 3 of `varlist'
	qui gen `wagemv'=`wage' if `touse'
	qui mvdecode `wagemv' if `touse',mv(0)

	dis "Computing a family of indices measuring well-being (monetary) gain/loss and social welfare loss associated with segregation based on disaggregated data."
	dis ""

	matrix `Wjg' =J(`: word count `lo'',`: word count `lw'',.)
	matrix `Wj' =J(`: word count `lo'',1,.)
	****************************************************************************
	if "`stats'"=="mean" {
		su `wagemv' [`weight' `exp'] if `touse',meanonly
		scalar `wtot'=r(mean)

		if (`wtot'==.){
			di as error "Error: The average status of the economy cannot be missing."
			exit
		}

		local i = 1
		foreach k of local lo {
		su `wagemv' [`weight' `exp'] if `touse' & `occp' == `k', meanonly
		matrix `Wj'[`i',1] = r(mean)
		local j = 1
			foreach m of local lw {
			su `wagemv' [`weight' `exp'] if `touse' & `occp' == `k' & `white' == `m', meanonly
				if missing(r(mean)) matrix `Wjg'[`i',`j']=`Wj'[`i',1]
				else matrix `Wjg'[`i',`j'] = r(mean)
			local ++j
			}
		local ++i
		}
	}
	****************************************************************************
	if "`stats'"=="median" {
		qui su `wagemv' [`weight' `exp'] if `touse',detail
		scalar `wtot'=r(p50)

		if (`wtot'==.){
			di as error "Error: The median status of the economy cannot be missing."
			exit
		}

		local i = 1
		foreach k of local lo {
		qui su `wagemv' [`weight' `exp'] if `touse' & `occp' == `k', detail
		matrix `Wj'[`i',1] = r(p50)
		local j = 1
			foreach m of local lw {
			qui su `wagemv' [`weight' `exp'] if `touse' & `occp' == `k' & `white' == `m', detail
				if missing(r(p50)) matrix `Wjg'[`i',`j']=`Wj'[`i',1]
				else matrix `Wjg'[`i',`j'] = r(p50)
			local ++j
			}
		local ++i
		}
	}
	****************************************************************************
	mata: st_matrix(st_local("index"),selectindex(rowmissing(st_matrix("`Wj'")):==0))
	mata: st_matrix(st_local("Wjg"),st_matrix("`Wjg'")[st_matrix("`index'"),.])
	mata: st_matrix(st_local("Wj"),st_matrix("`Wj'")[st_matrix("`index'"),.])
	mata: st_matrix(st_local("F"),st_matrix("`F'")[st_matrix("`index'"),.])
}
********************************************************************************
else {
	if length(`"`addstatus'"')!= 0 {
		preserve
		qui keep if `touse'
		sort `occp' `white'

		local wage "`callvar'"
		local mm=`"m:1"'

		merge `mm' `occp' using "`callfile'",keep(match) keepusing(`wage') nogenerate /*tamén podería pór quietly*/
		if length(`"`saving'"') != 0 save "`saving'.dta", replace
	}
	else{
		local wage:  word 3 of `varlist'
		if ("`wage'"==""){
			di as error "Error: A third argument (status) is required."
			exit
		}
	}

	if "`stats'"!="" {
		di "Warning: status does not vary in within-unit for different groups. Mean and median produce the same output."
	}

	dis ""
	dis "Computing a family of indices measuring well-being (monetary) gain/loss and social welfare loss associated with segregation based on aggregated (by unit) data."
	dis ""

	qui gen `wagemv'=`wage' if `touse'
	qui mvdecode `wagemv' if `touse',mv(0)
    su `wagemv' [`weight' `exp'] if `touse',meanonly
	scalar `wtot'=r(mean)

	if (`wtot'==.){
		di as error "Error: The average status of the economy cannot be missing."
		exit
	}

	matrix `Wj' =J(`: word count `lo'',1,.)
	local i = 1
	foreach k of local lo {
	 su `wagemv' [`weight' `exp'] if `touse' & `occp' == `k', meanonly
	 matrix `Wj'[`i',1] = r(mean)
	 local ++i
    }

	mata: st_matrix(st_local("index"),selectindex(rowmissing(st_matrix("`Wj'")):==0))
	mata: st_matrix(st_local("Wj"),st_matrix("`Wj'")[st_matrix("`index'"),.])
	mata: st_matrix(st_local("F"),st_matrix("`F'")[st_matrix("`index'"),.])
}
********************************************************************************

mata: st_matrix(st_local("rowtot"),rowsum(st_matrix("`F'"))) /* rows x 1 */
mata: st_matrix(st_local("coltot"),colsum(st_matrix("`F'"))) /* 1 x cols */
mata: st_matrix(st_local("RN"),rowsum(st_matrix("`coltot'")))

local  rn=`RN'[1,1]
local  rc=colsof(`F')
local  rr=rowsof(`F')
local occpdrop=`rr0'-`rr'
********************************************************************************
********************************************************************************
if "`aggregate'" =="" {
	matrix `Psi'   = J(5,`rc',0)
	matrix `Omega' = J(5,`rc',0)

	forvalues i = 1 / `rc' {
		forvalues j = 1 / `rr' {
		************************************************************************
        *epsilon=0
		matrix	`Psi'[1,`i']  = `Psi'[1,`i']  + ((`F'[`j',`i'] /`coltot'[1,`i'])-(`rowtot'[`j',1] / `rn'))*(`Wj'[`j',1]/`wtot')
		matrix `Omega'[1,`i']  = `Omega'[1,`i']  + (`F'[`j',`i'] /`coltot'[1,`i'])*((`Wjg'[`j',`i']/`wtot')-(`Wj'[`j',1]/`wtot'))
		************************************************************************
		*epsilon=1
		matrix	`Psi'[2,`i'] = `Psi'[2,`i']  + ((`F'[`j',`i'] /`coltot'[1,`i'])-(`rowtot'[`j',1] / `rn'))*ln(`Wj'[`j',1]/`wtot')
		matrix `Omega'[2,`i']  = `Omega'[2,`i']  + (`F'[`j',`i'] /`coltot'[1,`i'])*(ln(`Wjg'[`j',`i']/`wtot')-ln(`Wj'[`j',1]/`wtot'))
		************************************************************************
		*epsilon=2,3,4
		local k=3
		foreach epsilon of numlist 2 3 4 {
			matrix	`Psi'[`k',`i'] = `Psi'[`k',`i']  + (((`F'[`j',`i'] /`coltot'[1,`i'])-(`rowtot'[`j',1] / `rn'))*((`Wj'[`j',1]/`wtot')^(1-`epsilon')-1))/(1-`epsilon')
			matrix	`Omega'[`k',`i'] = `Omega'[`k',`i']  + ((`F'[`j',`i'] /`coltot'[1,`i'])*(((`Wjg'[`j',`i']/`wtot')^(1-`epsilon')-1)-((`Wj'[`j',1]/`wtot')^(1-`epsilon')-1)))/(1-`epsilon')
			local ++k
			}
		}
	}

	mata:	st_matrix(st_local("WAD"), st_matrix("`Psi'")+ st_matrix("`Omega'"))
	mata:	st_matrix(st_local("EgapAS"), st_matrix("`Psi'")[1,.]:/st_matrix("`WAD'")[1,.])

	if "`nograph'"~= "nograph" {
		matrix `Decomp'=`Psi'[1,1...]*100 \ `Omega'[1,1...]*100 \ `WAD'[1,1...]*100 \ `white'
		matrix `Decomp'=`Decomp''

		cap drop _Decomp*
		svmat `Decomp',names(_Decomp)

		graph bar (asis) _Decomp1 _Decomp2 in 1/`rc', over(_Decomp4) stack legend(label(1 "Segregation") label(2 "Within-unit status disparities") size(small))/*
		*/title("Decomposition of the per capita earning gap ratio (EGap x 100)", span size(medium))/*
		*/saving(grEGap,replace)

		cap drop _Decomp*
	}
}
********************************************************************************
else{
	matrix `Psi'   = J(5,`rc',0)

	forvalues i = 1 / `rc' {
		forvalues j = 1 / `rr' {
		******************************************************
        *epsilon=0
		matrix	`Psi'[1,`i']  = `Psi'[1,`i']  + ((`F'[`j',`i'] /`coltot'[1,`i'])-(`rowtot'[`j',1] / `rn'))*(`Wj'[`j',1]/`wtot')
		******************************************************
		*epsilon=1
		matrix	`Psi'[2,`i'] = `Psi'[2,`i']  + ((`F'[`j',`i'] /`coltot'[1,`i'])-(`rowtot'[`j',1] / `rn'))*ln(`Wj'[`j',1]/`wtot')
		******************************************************
		*epsilon=2,3,4
		local k=3
		foreach epsilon of numlist 2 3 4 {
			matrix	`Psi'[`k',`i'] = `Psi'[`k',`i']  + (((`F'[`j',`i'] /`coltot'[1,`i'])-(`rowtot'[`j',1] / `rn'))*((`Wj'[`j',1]/`wtot')^(1-`epsilon')-1))/(1-`epsilon')
			local ++k
			}
		}
	}
}
********************************************************************************
********************************************************************************
matrix `dtilde'   = J(5,`rc',.)
forvalues j = 1/`rc' {
	matrix `dtilde'[1 , `j']= abs(min(`Psi'[1 , `j'],`thr'))
	forvalues i = 2/5 {
		matrix `dtilde'[`i' , `j']= abs(min(`Psi'[`i', `j'],0))
	}
}

mata: st_matrix(st_local("dtildein"),st_matrix("`dtilde'"):!=0)
mata: st_matrix(st_local("pop"),st_matrix("`coltot'")/`rn')
mata: st_matrix(st_local("FGT"),rowsum(st_matrix("`pop'"):* st_matrix("`dtildein'")))

local k=1
foreach a of numlist 1 2 3{
	tempname FGT`k'
	mata: st_matrix(st_local("FGT`k'"),rowsum(st_matrix("`pop'"):* st_matrix("`dtilde'"):^`a'))
	matrix `FGT'=`FGT',`FGT`k''
	local ++k
}
********************************************************************************

cap drop _p*
cap drop _Wd*
cap drop _TIP*

local x "_p"
local y "_Wd"
local rc1=`rc'+1

mata : st_matrix(st_local("aux"),st_matrix("`pop'"):* st_matrix("`dtilde'"))

forvalues i=1/5 {
	tempname TIP`i'
	tempname Coords`i'
	mat `TIP`i'' = (`dtilde'[`i',1...] \ `pop'\ `aux'[`i',1...])'

	mata: st_matrix(st_local("TIP`i'"),sort(st_matrix("`TIP`i''"),(-1,2)))

	mat `TIP`i'' = `TIP`i''[1...,2..3]
	mat `TIP`i'' = (0 , 0) \ `TIP`i''

	svmat `TIP`i'',names(_TIP`i'_)
	ren _TIP`i'_1 `x'`i'
	ren _TIP`i'_2 `y'`i'

	qui replace `x'`i'=sum(`x'`i') in 1/`rc1'
	qui replace `y'`i'=sum(`y'`i') in 1/`rc1'

	mkmat `x'`i' `y'`i' in 1/`rc1',mat(`Coords`i'')

	qui replace `x'`i'=`x'`i'*100 in 1/`rc1'
	qui replace `y'`i'=`y'`i'*100 in 1/`rc1'
}

mat `Coord'=(`Coords1'[2...,.], `Coords2'[2...,.], `Coords3'[2...,.], `Coords4'[2...,.], `Coords5'[2...,.])

if "`nograph'"~= "nograph" {
	local xtitle "cumulative population share"
	local ytitle "cumulative sum of well-being losses divided by T"
	local graph_options "plotr(m(zero)) connect(l) lpattern(solid) lwidth(medium) lcolor(black) xtick(0(10)100) xlabel(0(10)100,labsize(small)) ylabel(,labsize(small)) xtitle("`xtitle'", size(small) ) ytitle("`ytitle'", size(small) )"

	local graphs ""
	forvalues i=1/5 {
		local j=`i'-1
		graph twoway line `y'`i' `x'`i' in 1/`rc1',`graph_options' title("{&epsilon} = `j'",size(small)) name(g`i', replace) nodraw
		local graphs "`graphs' g`i'"
	}
	graph combine `graphs', col(3) title("Social Welfare Loss curves associated with segregation (WLAS{sub:{&epsilon}} x 100)",size(small)) saving(grWLAS,replace)
}

cap drop _p* _Wd*
********************************************************************************
********************************************************************************
*Preparing results
if "`aggregate'" =="" {
	mat `rslt1'= ( `pop' \ `Psi' \ `Omega' \ `WAD' \ `EgapAS' )
	mat rownames `rslt1' = "share" Gamma_Psi0 Psi1 Psi2 Psi3 Psi4 Delta_Omega0 Omega1 Omega2 Omega3 Omega4 EGap_WAD0 WAD1 WAD2 WAD3 WAD4 seg_Egap
}
else{
	mat `rslt1'= ( `pop' \ `Psi' )
	mat rownames `rslt1' = "share" Gamma_Psi0 Psi1 Psi2 Psi3 Psi4
}

local r_rslt1=rowsof(`rslt1')
local n_rslt1=rowsof(`rslt1')*`rc'

local k=1
qui range `rslt1index' . `n_rslt1' `n_rslt1' /* Create n_rslt1 obs on index from . to n_rslt1 */
qui range `rslt1value' . `n_rslt1' `n_rslt1'
qui range `rslt1group' . `n_rslt1' `n_rslt1'
forvalues j= 1/`rc' {
	forvalues i=1/`r_rslt1 ' {
		qui replace `rslt1index'=`i' 			  if _n==`k'
		qui replace `rslt1value'=`rslt1'[`i',`j'] if _n==`k'
		qui replace `rslt1group'=`white'[1,`j']   if _n==`k'
		local ++k
	}
}

lab def `rslt1index' 1 "pop-share" 2 "Gamma:Psi{eps=0}" 3 "Psi{epsilon=1}" 4 "Psi{epsilon=2}" 5 "Psi{epsilon=3}" 6 "Psi{epsilon=4}" 7 "Delta:Omega{eps=0}" 8 "Omega{epsilon=1}" /*
*/ 9 "Omega{epsilon=2}" 10 "Omega{epsilon=3}" 11 "Omega{epsilon=4}" 12 "EGap:WAD{eps=0}"  13 "WAD{epsilon=1}" 14 "WAD{epsilon=2}" 15 "WAD{epsilon=3}" 16 "WAD{epsilon=4}" 17 "seg-EGap"
lab val `rslt1index' `rslt1index'
lab var `rslt1index' "Measures of well-being (monetary) gain/loss associated with segregation"

cap lab copy `white' `rslt1group'
cap lab val  `rslt1group' `rslt1group'
cap lab var  `rslt1group' "`white'"

********************************************************************************
mat colnames `Coord'= x(cumshare0) y(WLAS0) x(cumshare1) y(WLAS1) x(cumshare2) y(WLAS2) x(cumshare3) y(WLAS3) x(cumshare4) y(WLAS4)
mat colnames `FGT'= FGT0 FGT1 FGT2 FGT3
mat rownames `FGT'= epsilon0 epsilon1 epsilon2 epsilon3 epsilon4

local k=1
qui range `rslt2index' . 20 20
qui range `rslt2value' . 20 20
qui range `rslt2group' . 20 20
forvalues j= 1/4 {
	forvalues i=1/5 {
		qui replace `rslt2index'=`i' 			if _n==`k'
		qui replace `rslt2value'=`FGT'[`i',`j'] if _n==`k'
		qui replace `rslt2group'=`j'            if _n==`k'
		local ++k
	}
}

lab def  `rslt2index' 1 "epsilon=0" 2 "epsilon=1" 3 "epsilon=2" 4 "epsilon=3"  5 "epsilon=4"
lab val  `rslt2index' `rslt2index'
lab var  `rslt2index' "FGT indices"

lab def `rslt2group' 1 "alpha=0" 2 "alpha=1" 3 "alpha=2" 4 "alpha=3"
lab val `rslt2group' `rslt2group'
lab var `rslt2group' "Inequality aversion parameter"

********************************************************************************
********************************************************************************
*Reporting results
dis ""
dis as text "Number of units  (`occp') = " as result `rr'

if `occpdrop'!= 0 {
	di as result `occpdrop' as text " unit(s) dropped because no status is observed for any group."
    }
dis as text "Number of groups (`white') = " as result `rc'
dis ""

lab var `rslt1value' "Population shares"
tabdisp  `rslt1group' if `rslt1value'~=. & `rslt1index'==1,  c(`rslt1value')  f(`format') concise stubwidth(20) csepwidth(1) cellwidth(20)

lab var `rslt1value' "`white'"
tabdisp `rslt1index' `rslt1group'    if `rslt1value'~=. & `rslt1index'>1,  c(`rslt1value')  f(`format') concise stubwidth(20) csepwidth(1) cellwidth(20)

if "`aggregate'" =="" {
	dis "{bf:Psi_{epsilon}}=Family of indices to quantify the well-being gain/loss of a group associated with its segregation."
	dis "{bf:Omega_{epsilon}}=The well-being gain/loss of a group due to within-unit status disparities with respect to other groups."
	dis "{bf:WAD_{epsilon}}=Total well-being advantage/disadvantage (WAD) of a group: Psi_{epsilon} + Omega_{epsilon}."
	dis "{bf:seg-EGap}=Contribution of segregation to the per capita earning gap ratio (EGap=WAD_{0}) of the group: Psi_{0}/WAD_{0}."
	dis "{ul: Note 1} {it:epsilon={0,1,2,3,4}} is the constant elasticity of the assumed utility function that can be interpreted as a (relative) inequality aversion parameter in Psi_{epsilon} indices."
	dis "{ul: Note 2} {it:Gamma=Psi_{0}} measures the monetary gain/loss of a group associated with its segregation."
	dis "{ul: Note 3} {it:Delta=Omega_{0}} measures the monetary gain/loss of the group associated with within-unit status disparities with respect to other groups."
	if "`stats'"=="median"{
		dis as text "{ul: Note 4} All measures are computed using " as result "`stats'" as text " " as result "`wage'"  as text " in the economy and the unit. Default is mean."
	}
}
else{
	dis "{bf:Psi_{epsilon}}=Family of indices to quantify the well-being gain/loss of a group associated with its segregation."
	dis "{ul: Note 1} {it:epsilon={0,1,2,3,4}} is the constant elasticity of the assumed utility function that can be interpreted as a (relative) inequality aversion parameter in Psi_{epsilon} indices."
}

dis ""
tabdisp `rslt2index' `rslt2group' if `rslt2value'~=.,  c(`rslt2value')  f(`format') concise stubwidth(20) csepwidth(1) cellwidth(10)
dis "{bf:FGT_{alpha}}=The Foster-Greer-Thorbecke (FGT) family of poverty indices adapted to measure the social welfare loss that the society experiences due to segregation."

if "`aggregate'" =="" {
	dis "{ul: Note 1} {it:alpha={0,1,2,3}} is an inequality aversion parameter in FGT indices."
	dis "{ul: Note 2} {it:FGT_{alpha=0}} is the headcount ratio: fraction of the population that belongs to groups that have well-being (monetary) losses associated with segregation."
	if `thr'!=0{
		dis as text "{ul: Note 3} FGT indices are computed with threshold=" as result `thr' as text " for {it:epsilon}=0. Default is threshold=0."
	}
}
else{
	dis "{ul: Note 1} {it:alpha={0,1,2,3}} is an inequality aversion parameter in FGT indices."
	dis "{ul: Note 2} {it:FGT_{alpha=0}} is the headcount ratio: fraction of the population that belongs to groups that have well-being (monetary) losses associated with segregation."
	if `thr'!=0{
		dis as text "{ul: Note 3} FGT indices and WLAS curves are computed with threshold=" as result `thr' as text " for {it:epsilon}=0. Default is threshold=0."
	}
}

dis ""
dis "{bf:References:}"
dis as text `"Del Río, C. and Alonso-Villar, O. (2017), "Segregation and Social Welfare: A Methodological Proposal with an Application to the U.S.", Social Indicators Research, forthcoming. DOI: 10.1007/s11205-017-1598-0"'
dis as text `"Alonso-Villar, O. and Del Río, C. (2016), "Local segregation and well-being", The Review of Income and Wealth. DOI: 10.1111/roiw.12224"'
dis as text `"Del Río, C. and Alonso-Villar, O. (2015), "The Evolution of Occupational Seggregation in the United States, 1940-2010: Gains and Losses of Gender-Race/Ethnicity Groups", Demography, vol. 52(3), pp. 967-988. DOI:10.1007/s13524-015-0390-5"'
di "{hline 100}"

mat `rslt1'=`rslt1'[2...,.]
return matrix measures=`rslt1'
return matrix share=`pop'
return matrix FGT=`FGT'
return matrix xywlas=`Coord'
********************************************************************************
********************************************************************************
mata mata clear
end