// PROGRAM: Display tensensitivity results
// DESCRIPTION: Main program to display tesensitivity cpi estimation results
//              in stata console. [see help file]

// IMPLEMENTATION NOTES:
//   - handles tables in 4 major formats: treatment effect statistic intervals
//     and scalar tables of c-scale output and multiple breakdown points.
//     They are handled by _display_interval_data, _display_cscale_table, and
//     _display_breakdown_table respectively
//   - _write_header_cpi and _write_interval_data display the two parts of the
//     the table. _interval_format determines the widths of columns and numbers
//     formatting for a given set of results.
//   - _write_header_cscale and _write_scalar_data display the two parts of the
//     cscale table.
//   - _write_header_cpi and _write_scalar_data are used by _display_breakdown_table

program _tesen_display

	syntax [anything], [cscale breakdown first]

	tempvar cmax cqtls breakdown_table

	di _newline(1)

	// =========================================================================
	// 1. c-scale table
	// =========================================================================
	if "`cscale'" != ""{

		capture matrix `cmax' = r(cmax)
		local err = _rc
		if `err' != 0 {
			local cmax .
		}
		else if `cmax'[1,1] == . {
			local cmax .
		}

		capture matrix `cqtls' = r(cquantiles)
		local err = _rc
		if `err' != 0 {
			local cqtls .
		}
		else if `cqtls'[1,1] == . {
			local cqtls .
		}

		_display_cscale_table `cmax' `cqtls'

	}
	// =========================================================================
	// 2. breakdown point table
	// =========================================================================
	else if "`breakdown'" != "" {

		if "`first'" == "" {
			local first .
		}

		if "`anything'" != ""{

			local nresults : word count `anything'
			matrix `breakdown_table' = J(1, `nresults', .)

			local iresult = 1
			foreach result of local anything {
				qui estimates restore `result'
				matrix `breakdown_table'[1, `iresult'] = `e(c_breakdown)'
				local stats `"`stats' `result'"'
				local iresult = `iresult' + 1
			}
			matrix colnames `breakdown_table' = `stats'
			matrix rownames `breakdown_table' = `"stat_>_`=e(y_breakdown)'"'
		}

		_display_breakdown_table `breakdown_table' `first'

	}
	// =========================================================================
	// 3. interval data table
	// =========================================================================
	else {

		tempvar c_table

		if "`anything'" != ""{
			gettoken result anything : anything
			qui estimates restore `result'
			matrix `c_table' = e(c_table)
			local stats `"`stats' `result'"'

			foreach result of local anything {
				qui estimates restore `result'
				mata: merge_matrices("`c_table'", "e(c_table)", "`c_table'", 1, 1)
				local stats `"`stats' `result'"'
			}
			local c_breakdown = .
			local y_breakdown = .
			local nobs = .
		}
		else {
			matrix `c_table' = e(c_table)
			local c_breakdown = e(c_breakdown)
			local y_breakdown = e(y_breakdown)
			local nobs = e(N)
			local stats `e(stat)'
		}

// 		mata: sort_st_matrix("`c_table'", 1)

		_display_interval_data `c_table' `c_breakdown' `y_breakdown' `nobs' `"`stats'"'

	}

end

// PROGRAM: display interval data
// DESCRIPTION: Display table of interval bounds for each statistic included
//              for set of c-dependence values
// INPUT:
//    - c_table: matrix, column 1 - c-dependence values,
//                       additional columns - pairs of lower, upper bounds
//    - c_breakdown: scalar, breakdown point. Only used for a set estimates.
//                           "." to exclude from header.
//    - y_breakdown: scalar, conclusion threshold for breakdown point
//                           (e.g, ate > `y_breakdown'), "." to exclude from header
//    - nobs: scalar, number of observations
//    - stats: string, list of statistic names (used in column headers)
// IMPLEMENTATION NOTES:
//    - Currently no customizable formatting options
//    - TODO: currently must have same c-dependence values for multiple estimates
program _display_interval_data

	// process input
	args c_table c_breakdown y_breakdown nobs stats
	local nestimates : word count `stats'

	// =========================================================================
	// 1. set display options
	// =========================================================================

	// global default display settings
	local left_colon = 18 // placement of colon in left column of header
	local right_col  = 48 // start of right column
	local equal_col  = 63 // placement of = in right column
	local right_bord = 80 // total width of table

	local labels_width 20 // width of left column with c-dependence values
	local n_dig 3         // number of decimal points for c-dependence values

	// header information
	if `nestimates' == 1 {
		local analysis cond. partial independence
		local tmodel `e(tmodel)'
		local omodel `e(omodel)'
		local depvar `e(depvar)'
		local stat `stats'
	}
	else {
		local analysis conditional partial independence, multiple results
		local tmodel .
		local omodel .
		local depvar .
		local stat .
	}

	// =========================================================================
	// 2. write header
	// =========================================================================
	_write_header_cpi `nobs' `c_breakdown' `y_breakdown' `n_dig'         ///
					  `left_colon' `right_col' `equal_col' `right_bord'  ///
					  "`analysis'" "`tmodel'" "`omodel'" `depvar' `stat'

	// =========================================================================
	// 3.1 determine formatting specification for intervals
	// =========================================================================
	// NOTES:
	//   - table consists of a left column for c-dependence values, and
	//     one column for each estimates included. Have to determines
	//     the formatting and width of the column for each estimate.
	//   - _interval_format returns the width and formatting
	//   - formats heading for the table itself (i.e., "c | ate qte" etc.)
	//   - formats the horizontal lines forming the table

	// starting values for location of first statistic
	local stat_start = 2 + `labels_width' // starting display column for interval data
	local stat_num 2 // column number of c_table where the first stat starts

	// interval table header up to start of statistic labels (these are the
	// labels for the table itself, not the text above the table)
	local tbl_header `"as text  _col(`=`labels_width' - 2') "c" "'

	// horizontal bars making table up to start of first statistic
	local hbar_top `"{hline `=`labels_width' - 2'}"'
	local hbar_mid `"{hline `=`labels_width' - 2'}"'
	local hbar_bot `"{hline `=`labels_width' - 2'}"'

	// determine widths and formatting of columns for each stat
	foreach stat in `stats'{
		matrix int_tbl = `c_table'[1...,`stat_num'..`=`stat_num' + 1']
		_interval_format int_tbl // interval width + fmt for current stat
		local interval_width `s(int_width)'
		local int_formats `int_formats' `s(int_format)'
		local int_widths `int_widths' `interval_width'

		// update starting location for next statistic
		local stat_start = `stat_start' + `interval_width' - strlen("`stat'")
		local hbar_len = 1 + `interval_width'

		// update header and table bars
		local tbl_header `"`tbl_header' " {c |}" _col(`stat_start') as text "`stat'""'
		local hbar_top `"`hbar_top'{hline 1}{c TT}{hline `hbar_len'}"'
		local hbar_mid `"`hbar_mid'{hline 1}{c +}{hline `hbar_len'}"'
		local hbar_bot `"`hbar_bot'{hline 1}{c BT}{hline `hbar_len'}"'

		// update display column and column in c_table for the next stat
		local stat_start = `stat_start' + strlen("`stat'") + 3
		local stat_num = `stat_num' + 2
	}

	// =========================================================================
	// 3.2 Write interval data
	// =========================================================================
	di as text "`hbar_top'"
	di `tbl_header'
	di as text "`hbar_mid'"
	_write_interval_data `"`int_formats'"' `"`int_widths'"' `labels_width' `n_dig' `c_table'
	di as text "`hbar_bot'"

end

// PROGRAM: Write header for conditional partial independence analysis
// DESCRIPTION: Writes a header above the table which includes the information
//              included in the teffects output as well as the breakdown
//              conclusion and breakdown point
// INPUT:
//    - nobs: scalar, number of observations
//    - breakdown: scalar, breakdown point (c-dependence), "." to exclude
//    - y_breakdown: scalar, breakdown conclusion, "." to exclude
//    - bd_dig: scalar, number of decimal points for breakdown point
//    - left_colon: scalar, display column for colon in left column
//    - right_col: scalar, display column for start of right column
//    - equal_col: scalar, display column for equal sign in right columns
//    - right_bord: scalar, display column for total width of table
//    - analysis: string, name of analysis
//    - tmodel: string, treatment model
//    - omodel: string, outcome model
//    - depvar: string, dependent variable
//    - stat: string, name of statistic used in analysis (only for single estimate),
//                    "." to exclude
//    - first: string, when multiple tables are displays this controls which
//                     table includes that overall title. "first" to include
//                     title, "." to exclude (not first)
// IMPLEMENTATION NOTES:
program _write_header_cpi

	args nobs breakdown y_breakdown bd_dig left_colon right_col equal_col right_bord ///
	     analysis tmodel omodel depvar stat first

	// =========================================================================
	// 1. Calculate formatting paramters
	// =========================================================================
	local right_col_width = `right_bord' - `equal_col' - 1
	local conject_width = `right_bord' - `equal_col' - strlen("`stat'") - 3 - 1
	local y_breakdown = strofreal(`y_breakdown', "%`conject_width'.0gc")

	// =========================================================================
	// 2. Form header elements
	// =========================================================================

	// left column elements
	local lc_head `"as text "Treatment effects sensitivity""'
	local lc_analysis `"as text "Analysis" _col(`left_colon') as result ": `analysis'""'

	local lc_outcome_mod `"as text "Outcome model" _col(`left_colon') as result ": `omodel'""'
	local lc_treat_mod `"as text "Treatment model" _col(`left_colon') as result ": `tmodel'""'
	local lc_depvar `"as text "Outcome variable" _col(`left_colon') as result ": `depvar'""'


	// right column - number observations
	if "`nobs'" != ""{
		local obs_l1 `"_col(`right_col') as text "Number of obs" _col(`equal_col') "=""'
		local obs_l2 `"as result %`right_col_width'.0f `nobs'"'
		local rc_obs `"`obs_l1' `obs_l2'"'
	}

	// right columne - breakdown point
	if "`y_breakdown'" != "." {
		local bd_l1 `"_col(`right_col') as text "Breakdown" _col(`equal_col') "=""'
		local bd_l2 `" as result %`right_col_width'.`bd_dig'f `breakdown'"'
		local rc_bd `"`bd_l1' `bd_l2'"'

		local conject_l1 `"_col(`right_col') as text "Conclusion" _col(`equal_col') "=""'
	    local conject_l2 `"as result %`right_col_width's "`stat' > `y_breakdown'""'
		local rc_conject `"`conject_l1' `conject_l2'"'
	}

	// =========================================================================
	// 3. Write the header
	// =========================================================================
	if "`first'" != "." {
		di `lc_head'
	}
	// if a statistic is specified, this is a table for a single estimates:
	// include the full header
	if "`stat'" != "." {
		di `lc_analysis' `rc_obs' _newline /*
		*/`lc_outcome_mod' `rc_bd' _newline /*
		*/`lc_treat_mod' `rc_conject' _newline /*
		*/`lc_depvar'
	}
	// if no statistic is specified, this is table combining estimates:
	// include a shortened header (most of the information is specific to
	// a single estimate so can't include it)
	else {
		di `lc_analysis'
	}
end

// PROGRAM: Write interval data
// DESCRIPTION: Writes the intervals data given formatting information. If
//              reference c-depednence values were included, writes the name of the
//              covariates in the left column
// INPUT:
//   - fmts: string, list of formats for each estimate
//   - widths: string, list of widths for each interval_width
//   - lab_width: scalar, end display column of left column with c-values
//   - c_digits: scalar, number of decimals for c-dependence values
//   - c_table: matrix, column 1 - c-dependence values,
//                       additional columns - pairs of lower, upper bounds
// IMPLEMENTATION NOTES:
//   - number formatting is consistent for each statistic
//   - reference c-dependence values in the c_table have the name of the
//     corresponding covariate in the rowname of the matrix. The rowname
//     of c-depedence values that are part of the grid are just called
//     grid#
program _write_interval_data

	args fmts widths lab_width c_digits c_table
	tempname cval

	// =========================================================================
	// 1. Determine formatting parameters
	// =========================================================================
	local nrows = rowsof(`c_table')
	local ncols = (colsof(`c_table') - 1) / 2 // number of display columns (not columns in c_table)
	local rnames : rownames(`c_table')
	local c_start = `lab_width' - `c_digits' - 3 // display column of c values
	local cov_width = `lab_width' - `c_digits' - 5 // width for ref c vals

	// =========================================================================
	// 2. Write table lines
	// =========================================================================
	// - outer loop - rows, inner loop - columns
	forvalues row = 1/`nrows' {

		// clear macro that will have row text
		local covname
		local intervals

		// get covariate name if reference c-dependence value
		local rname : word `row' of `rnames'
		if !strmatch("`rname'", "grid*") {
			local covname `"as result %-`cov_width's abbrev("`rname'", `cov_width')"'
		}

		// get c-dependence value
		scalar `cval' = `c_table'[`row', 1]

		// inner loop: add text to row text macro for one stat at a time
		forvalues col = 1/`ncols'{

			local f : word `col' of `fmts' // format for interval data
			local lower_col = 2 + (2 * `=`col'-1') // c_table column for lw bd
			local upper_col = `lower_col' + 1 // c_table column for up bd
			local lval = `c_table'[`row', `lower_col'] // lw bd value
			local uval = `c_table'[`row', `upper_col'] // up bd value
			// add stat interval text
			local intervals `"`intervals' as text " [" as result `f' `lval' as text ", " as result `f' `uval' as text "]" "'
			// if last column add vertical line
			if `col' < `ncols'{
				local intervals `"`intervals' " {c |}""'
			}

		}

		// write the row
		di `covname' _col(`c_start') as text %`=1 + `c_digits''.`c_digits'f `cval' " {c |}" `intervals'

	}

end

// PROGRAM: Interval formatting
// DESCRIPTION: determines the width of each interval in the table and
//              formatting of the numbers
// INPUT: c_table: The table of intervals, column 1 - c values, columns 2,3
//                 lower and upper bounds
// RETURN:
//   - s(int_format), formatting string for data in this estimate
//   - s(total width), total column width for this estimate
// NOTES:
//   - This can only handle one estimate at a time
//   - These are hard coded for now. For values between -10, 10,
//     shown with 4 decimals, for [10, 1000), 2 decimals, [1,000, 1,000,000)
//     no decimals and full numbers, for > 1,000,000 shown in scientific format
program _interval_format, sclass

	args c_table

	// get the number of integer digits
	mata: m1 = st_matrix("`c_table'")[,1]
	mata: m1 = abs(m1)
	mata: m2 = st_matrix("`c_table'")[,2]
	mata: m2 = abs(m2)
	mata: st_numscalar("minval", min((m1, m2)))
	mata: m = max((floor(colmax(m1)), floor(colmax(m2))))
	mata: nchar = floor(log10(m)) + 1
	mata: st_local("nchar", strofreal(nchar))
	mata: mata drop nchar m1 m2 m
	if `nchar' == . local nchar 0

	// Cases for different numbers of digits
	if `nchar' <= 1 & minval < 10 & minval >= .0001{
		local ndig = 4
		local num_len = 1 + `ndig' + 2
		local int_format "%`num_len'.`ndig'f"
		local int_width = (`num_len' * 2) + 4
	}
	else if `nchar' <= 1 & minval < .0001{
		local ndig = 3
		local num_len = `ndig' + 6
		local int_format "%`num_len'.`ndig'e"
		local int_width = (`num_len' * 2) + 4
	}
	else if `nchar' >= 2 & `nchar' <= 3{
		local ndig = 2
		local num_len = `nchar' + `ndig' + 2
		local int_format "%`num_len'.`ndig'fc"
		local int_width = (`num_len' * 2) + 4
	}
	else if `nchar' >= 4 & `nchar' <= 6 {
		local num_len = `nchar' + 2
		local int_format "%`num_len'.0fc"
		local int_width = (`num_len' * 2) + 4
	}
	else if `nchar' >= 7 & `nchar' <= 9  {
		local num_len = `nchar' + 3
		local int_format "%`num_len'.0fc"
		local int_width = (`num_len' * 2) + 4
	}
	else if `nchar' >= 10{
		local ndig = 3
		local num_len = `ndig' + 6
		local int_format "%`num_len'.`ndig'e"
		local int_width = (`num_len' * 2) + 4
	}

	sreturn local int_format `int_format'
	sreturn local int_width `int_width'

end

// PROGRAM: Display c-dependence scale table
// DESCRIPTION: Write table for output of tesensitivity cscale
// INPUT:
//   - cmax, include the supremum of the distribution, "." to exclude
//   - quantiles, list of quantiles of the distribution
program _display_cscale_table

	args cmax quantiles

	// =========================================================================
	// 1. formatting paramteres
	// =========================================================================

	// global default display settings
	local left_colon = 18 // placement of colon in left column of header
	local right_col  = 55 // start of right column
	local equal_col  = 70 // placement of = in right column
	local right_bord = 80 // total width of table

	local lbl_width 14
	local ndig  = 3
	local colspace = 3
	local max_width = `colspace' + 2 + `ndig'

	// start bars and column header
	local colnames `"as text %`lbl_width's "quantile""'
	local hbar_top `"{hline `lbl_width'}"'
	local hbar_mid `"{hline `lbl_width'}"'
	local hbar_bot `"{hline `lbl_width'}"'

	// =========================================================================
	// 2. determine formatting specification for each column
	// =========================================================================
	if "`quantiles'" != "."{

		// load specificaiton of quantiles table
		local ncols = colsof(`quantiles') + 1
		local varnames : rownames(`quantiles')
		local qts : colnames(`quantiles')
		local colnames `"`colnames' as text " {c |}""'

		// form header of quantiles columns
		foreach qt of numlist `qts' {
			local colnames `"`colnames' as text %`=`ndig'+`colspace' + 2'.`ndig'f `qt'"'
		}
		local ncol : word count `qts'
		local hbar_len = ((`ndig' + `colspace' + 2) * `ncol')

		local stcol = 2 + `lbl_width' + `colspace' + (`ncol' * (2 + `ndig' + `colspace'))
		local hbar_top `"`hbar_top'{hline 1}{c TT}{hline `hbar_len'}"'
		local hbar_mid `"`hbar_mid'{hline 1}{c +}{hline `hbar_len'}"'
		local hbar_bot `"`hbar_bot'{hline 1}{c BT}{hline `hbar_len'}"'

	}

	if "`cmax'" != "." {
		local colname `"as text %`max_width's "max""'
		local colnames `"`colnames' " {c |}" `colname'"'
		local hbar_top `"`hbar_top'{hline 1}{c TT}{hline `max_width'}"'
		local hbar_mid `"`hbar_mid'{hline 1}{c +}{hline `max_width'}"'
		local hbar_bot `"`hbar_bot'{hline 1}{c BT}{hline `max_width'}"'
	}

	_write_header_cscale `e(N)' `left_colon' `right_col' `equal_col' `right_bord'
	di as text "`hbar_top'"
	di `colnames'
	di as text "`hbar_mid'"
	_write_scalar_data `lbl_width' `ndig' `colspace' `cmax' `quantiles'
	di as text "`hbar_bot'"

end

// PROGRAM: Write cscale header
// DESCRIPTION: Write header for output of tesensitivity cscale
// INPUT:
//   - nobs, scalar: number of observations

program _write_header_cscale

	args nobs left_colon right_col equal_col right_bord

	// input information
	local analysis leave one out prop. score diff.
	local tmodel logistic

	// alignment
	local right_col_width = `right_bord' - `equal_col' - 1

	di as text "Treatment-effects sensitivity analysis"
	di as text "Analysis" _col(`left_colon') as result ": `analysis'" /*
	*/ _col(`right_col') as text "Number of obs" _col(`equal_col') "="/*
	*/ as result %`right_col_width'.0g `nobs'
	di as text "Treatment model" _col(`left_colon') as result ": `tmodel'"

end

// PROGRAM: Write scalar data
// DESCRIPTION: write table of scalar data
// INPUT:
//   - st_width, scalar: width of left side labels
//   - ndig, scalar: number of decimals in numbers
//   - colspace, scalar: width between columns
//   - maxvals, matrix: right column
//   - vals, matrix: middle columns

program _write_scalar_data

	args st_width ndig colspace maxvals vals
	tempname val maxval

	// formatting specification
	local max_width = `colspace' + 2 + `ndig'

	// load specification of table
	if "`vals'" != "."{
		local ncols = colsof(`vals')
		local nrows = rowsof(`vals')
		local lbls : rownames(`vals')
	}
	else if "`maxvals'" != "." {
		local ncols = 0
		local nrows = rowsof(`maxvals')
		local lbls : rownames(`maxvals')
	}
	else {
		di as err "tesensitivity display scalar table" ///
        "no data found"
        exit 301
	}

	// write table row by row
	forvalues row = 1/`nrows' {

		// clear row input
		local valinput `"as text " {c |}""'

		// form inner table
		if "`vals'" != "." {
			forvalues col = 1/`ncols' {
				local val_`col' = `vals'[`row', `col']
				local col_loc = 2 + `st_width' + `colspace' + ((2 + `colspace' + `ndig') * (`col' - 1))
				local valinput `"`valinput' as result %`=2 + `ndig' + `colspace''.`ndig'f `val_`col'' "'
			}
			if "`maxvals'" != "."{
				local valinput `"`valinput' as text " {c |}""'
			}
		}
		// form right side table
		if "`maxvals'" != "."{
			scalar `maxval' = `maxvals'[`row', 1]
			local valinput `"`valinput' as result %`max_width'.`ndig'f `maxval' "'
			}

		// add line, including label
		local lbl1 : word `row' of `lbls'
		local lbl1 = subinstr("`lbl1'", "_", " ",.)
		di as text %`st_width's abbrev("`lbl1'", `st_width') `valinput'
	}

end

// PROGRAM: Display breakdown table
// DESCRIPTION: ...
program _display_breakdown_table

	args breakdown_tbl first

	// global display settings
	local labels_width 17
	local ndig  = 3
	local colspace = 7
	local left_colon = 17
	local colwidth = 2 + `colspace' + `ndig'

	// header
	_write_header_cpi . . . . `left_colon' . . . `"breakdown point, multiple"' . . . . `first'

	// start bars and column header
	local colnames `"as text %`labels_width's "conclusion""'
	local hbar_top `"{hline `labels_width'}"'
	local hbar_mid `"{hline `labels_width'}"'
	local hbar_bot `"{hline `labels_width'}"'

	// load specificaiton of breakdown table
	local ncols = colsof(`breakdown_tbl')
	local varnames : rownames(`breakdown_tbl')
	local qts : colnames(`breakdown_tbl')
	local colnames `"`colnames' as text " {c |}""'

	// form header of breakdown table
	local col 0
	foreach qt in `qts' {
		local q`col' `qt'
		local colname `"as text %`colwidth's abbrev("`q`col''", `=`colwidth' - 1')"'
		local colnames `"`colnames' `colname'"'
		local col = `col' + 1
	}
	local hbar_len = `colwidth' * `ncols'
	local hbar_top `"`hbar_top'{hline 1}{c TT}{hline `hbar_len'}"'
	local hbar_mid `"`hbar_mid'{hline 1}{c +}{hline `hbar_len'}"'
	local hbar_bot `"`hbar_bot'{hline 1}{c BT}{hline `hbar_len'}"'

	di as text "`hbar_top'"
	di `colnames'
	di as text "`hbar_mid'"
	_write_scalar_data `labels_width' `ndig' `colspace' . `breakdown_tbl'
	di as text "`hbar_bot'"

end

program merge_matrix_rownames
	args mat1 mat2

end

mata:
  	// mata drop merge_matrices()
	// Adapted from https://theesspreckelsen.wordpress.com/2014/07/21/
	//             merge-for-mata-combining-two-matrices-using-a-column-of-id-values-stata-merge-for-mata/
	// FUNCTION: Merge Matrices

	function merge_matrices(string scalar matm,
					        string scalar matu,
							string scalar matto,
							scalar posIDm,
							scalar posIDu)
	{
		m = st_matrix(matm)
		u = st_matrix(matu)
		m_name = st_matrixrowstripe(matm)
		u_name = st_matrixrowstripe(matu)

		idvalues = uniqrows(m[1..rows(m),posIDm]\u[1..rows(u),posIDu])

		fm = J(rows(idvalues),cols(m),.)
		fm_name = J(rows(idvalues), 2, "")
		for(i=1; i<=rows(idvalues); i++){
			for(j=1; j<=rows(m); j++){
				if (idvalues[i,1] == m[j,posIDm]) {
					fm[i,1..cols(m)] = m[j,]
					fm_name[i,] = m_name[j,]
					break
				}
			}
		}

		fu = J(rows(idvalues),cols(u),.)  //matrix collecting expanded mat.
		fu_name = J(rows(idvalues), 2, "")
		for(i=1; i<=rows(idvalues); i++){
			for(j=1; j<=rows(u); j++){
				if (idvalues[i,1] == u[j,posIDm]) {
					fu[i,1..cols(u)] = u[j,]
					fu_name[i,] = u_name[j,]
					break
				}
			}
		}
		// check and merge the column names

		fn = J(rows(idvalues), 2, "")
		for(i=1; i<=rows(fm_name); i++){
			s1 = fu_name[i,]
			s1ref = fu_name[i,1] == "cref"
			s2 = fm_name[i,]
			s2ref = fm_name[i,1] == "cref"

			if ((s1ref & !s2ref) | (s1ref & s2ref & (s1 == s2))) {
				fn[i,] = s1
			}
			else if (s2ref & !s1ref) {
				fn[i,] = s2
			}
			else {
				fn[i,] = ("grid", "grid`i'")
			}
		}

		f = idvalues,fm[,2..cols(fm)],fu[,2..cols(fm)]

		st_matrix(matto,f)
		st_matrixrowstripe(matto, fn)

	}
end