program define flexelasticity, rclass
*!	program flexelasticity		version 1.4		4May2018
	syntax varlist (min=1 max=2 fv),  ///
		[cmdline(string) atspecs(string) shares(string) actual omitshare(string) ///
		chain(passthru) chainlhs(passthru) chainwrt(passthru)]

	if `"`cmdline'"'=="" {
		if `"`e(cmdline)'"'=="" {
			di as err "The option cmdline(string) is omitted and e(cmdline) is empty."  ///
				_n "When the user omits the cmdline(string) option, this program expects"  ///
				_n "to find a command line stored in e(cmdline) by a previous estimation command."
			exit 198
		}
		else {
			local cmdline `e(cmdline)'
		}
	}

	if strpos(`"`cmdline'"',"##") > 0 {
		di as err "The option -cmdline- contains the two-character combination -##- which -flexelasticity- cannot parse." ///
			_n "Expand the -cmdline- so that any expression like " ///
			as res "c.x##c.y" as err " becomes " as res "c.x c.y c.x#c.y" as err " ."
			exit 198
	}

	foreach ch in chain chainlhs chainwrt {
		if strpos(`"``ch''"',"log10") | strpos(`"``ch''"',"sqrt") | strpos(`"``ch''"',"bc") {
			di as err "Warning: this program has not been validated for transformations other than -ln-"  ///
				_n "Computations continue but results are suspect."
		}
	}

	//	Break the command line up into chunks
	//	Assumes the command line can be parsed on spaces and a colon
	//	and that the first two tokens are the name of the equation
	//	and the dependent variable.
	cleancmdline, cmdline(`"`cmdline'"')
		local depvar `r(depvar)'
		local estcmd `r(estcmd)'
		local cmdline `r(cmdline)'
		local origcmdline `r(origcmdline)'

	tokenize `varlist'

	local wrt1 `1'
	local wrt2 `2'

*	Check to see if one or both of the "variables" is a share
*	This check only works if the shares option contains the names of the share variables, not their equation numbers
	local wrt1isshare : list posof "`wrt1'" in shares  // = 0 if -wrt1- not a share
	local wrt2isshare : list posof "`wrt2'" in shares  // = 0 if -wrt2- not a share

	if "`wrt2'"== "" { // Only one argument, so elasticity of dependent variable w.r.t. -wrt1-
		// If a translog function, this is simply
		qui firstpartial `wrt1', cmdline(`estcmd' `cmdline') `chain' `chainlhs' `chainwrt'
		if "`chain'`chainlhs'`chainwrt'"=="" {
			di _n as txt "Elasticity of Total Cost with respect to: " as res "`wrt1'" _n
			margin , expression(`r(expression)') `atspecs'
		}
		if "`chain'`chainlhs'`chainwrt'"~="" {
			di _n as txt "Partial deriviative of Total Cost with respect to the antilog of: " as res "`wrt1'"
			margin , expression(`r(margexpression)') `atspecs'
		}
	}
	else {  // Two arguments, so cross elasticity between -wrt1- and -wrt2-
		if `wrt1isshare'==0 & `wrt2isshare'==0 {  //  Use a coefficient from the cost function
			if "`chain'`chainlhs'`chainwrt'"~="" {
				di as err "Warning: -chain- options ignored when there are two variables listed"
			}

			local onebeforetwo c.`wrt1'#c.`wrt2'
			local twobeforeone c.`wrt2'#c.`wrt1'

			tokenize `cmdline'

			local coefofsqrdterm
			while "`1'"~="" {
				if strmatch("`1'","*`onebeforetwo'*")==1  | ///
				   strmatch("`1'","*`twobeforeone'*")==1  {
					if	strmatch("`1'","*`onebeforetwo'*")==1  {
						if strmatch("`1'","*__half*")==1 {
							local coefofsqrdterm _b[`onebeforetwo'#c.__half]
							local divisor = 1
						}
						else {
							local coefofsqrdterm _b[`onebeforetwo']
							local divisor = 2
						}
					}
					if	strmatch("`1'","*`twobeforeone'*")==1  {
						if "`coefofsqrdterm'"~="" & ("`onebeforetwo'"~="`twobeforeone'" ) {
							di _n as err "The two terms `onebeforetwo' and `twobeforeone' should not be in the same regression"
							exit 198
						}
						if strmatch("`1'","*__half*")==1 {
							local coefofsqrdterm _b[`twobeforeone'#c.__half]
							local divisor = 1
						}
						else {
							local coefofsqrdterm _b[`twobeforeone']
							local divisor = 2
						}
					}
				}
				macro shift
			}
			if "`coefofsqrdterm'"==""   {
				if "`wrt1'" == "`wrt2'"  {
					di as err "A term interacting `wrt1' with itself (i.e. a squared term in `wrt' of the form c.`wrt1'#c.`wrt1')"  ///
						_n as err "does not appear in the command line"
				}
				else {
					di as err "An interaction term between the two variables `wrt1' and `wrt2' does not appear in the command line"
				}
				exit 198
			}
		}
		else {  // Since `wrt1isshare' and/or `wrt2isshare' equals 1, use coefficient from the share equation

			if `wrt1isshare'==1 & `wrt2isshare'==1 { // Both wrts are shares
				if "`wrt1'"~="`wrt2'" {
					di _n as err "If both arguments are shares, both must be the same share."
					exit 198
				}
				local coefofsqrdterm _b[`wrt1':_cons]
			}
			else {  // One of wrt's is a share
				if `wrt1isshare'==1 {
					local coefofsqrdterm _b[`wrt1':`wrt2']
				}
				else {
					local coefofsqrdterm _b[`wrt2':`wrt1']
				}
			}
		}
		if "`shares'"=="" {

*	Following expression is from general definition of
*	elasticity as (C*d2_C/dKdL) / (dC/dK * dC/dL)
*	But must check that the log transform is unwound
			firstpartial  `wrt1' , cmdline(`estcmd' `cmdline')
				local d_ln_TC_d_wrt1 `r(expression)'
			firstpartial  `wrt2' , cmdline(`estcmd' `cmdline')
				local d_ln_TC_d_wrt2 `r(expression)'
			margin , expression(  -  ///
				(predict(xb))*(`coefofsqrdterm')		///
									/                	///
				((`d_ln_TC_d_wrt1')*(`d_ln_TC_d_wrt2'))	///
				) `atspecs'
		}
		else {
*	Specific to the translog we have:
			tokenize `shares'
			capture confirm integer number `1'
			if _rc == 0 {  // Check to see if share equations are indicated by numbers
				local hash #  //  If so, add the hash prefix
			}
			if "`actual'"=="" {
				local bottomlabel Equations
			}
			else {
				local bottomlabel Variables
				confirm numeric variable `1'
				confirm numeric variable `2'
			}
			if "`wrt1'"=="`wrt2'"|"`1'"=="`2'" {
				di _n as txt "Own-price elasticity when variables match and shares match:" ///
					_n "    Right-hand-side         Share  " ///
					_n "       Variables          `bottomlabel'" ///
					_n "  ------------------------------------"
				di as res "    `wrt1'"             _col(30) "`1'"
				di as res "    `wrt2'"             _col(30) "`2'"

/*
				if "`wrt1'"~="`wrt2'"|"`1'"~="`2'" {
					di _n as err "To compute an own-price elasticity, specify matching variables and matching shares."
					exit 198
				}
*/
				if "`actual'"=="" {  //  Use fitted shares
					margin, expression(  ///
						xb(`hash'`1')*(`coefofsqrdterm' + xb(`hash'`1') * (xb(`hash'`1')-1))/(xb(`hash'`1') * xb(`hash'`1'))) `atspecs'
				}
				else {
					margin, expression(  ///
						`1'*(`coefofsqrdterm' + `1' * (`1'-1))/(`1' * `1')) `atspecs' force
				}
			}
			else {
				di _n as txt "Elasticity between factors represented by:" ///
					_n "    Right-hand-side         Share  " ///
					_n "       Variables          `bottomlabel'" ///
					_n "  ------------------------------------"
				di as res "    `wrt1'"             _col(30) "`1'"
				di as res "    `wrt2'"             _col(30) "`2'"

				if "`actual'"=="" {  //  Use fitted shares
					margin, expression(  ///
						( `coefofsqrdterm' + xb(`hash'`1') * xb(`hash'`2'))/(xb(`hash'`1') * xb(`hash'`2'))) `atspecs'
				}
				else {
					margin, expression(  ///
						( `coefofsqrdterm' + `1' * `2')/(`1' * `2')) `atspecs' force
				}
			}
		}
	}
	tempname table sigma se_sigma
	mat def `table' = r(table)
	scalar `se_sigma' = `table'[2,1]
	scalar `sigma' = `table'[1,1]

	return scalar p_sigma = `table'[4,1]
	return scalar se_sigma = `se_sigma'
	return scalar sigma = `sigma'
	return add

end		// End of program flexelasticity

/*
program cleancmdline, rclass
*	Version 1.2 by Mead Over 19Aug2016
*	This programs accepts the command line from either a single or a
*	multiequation estimator and returns a simplified command line which
*	begins with the dependent variable.  For a multiequaiton command like
*	-sureg- or -reg3-, this program strips e(cmdline) of the estimation command,
*	the equation name (identified because it is followed by a colon) and all
*	parentheses.

	syntax , cmdline(string)

	//	Break the command line up into chunks
	//	Assumes the command line can be parsed on spaces and a colon
	//	and that the first two tokens are the name of the equation
	//	and the dependent variable.

	local origcmdline `cmdline'
	tokenize `"`cmdline'"', parse(" (")

	// If the first or second token in the command line is a left parenthesis,
	// strip everything up to the -(- character from the beginning of the -cmdline-
	if "`1'"=="(" | "`2'"=="(" {
		local cmdline = substr(`"`cmdline'"',strpos(`"`cmdline'"',"(")+1,.)

		//	If the second token was a -(-, then the first is an estimation command
		if "`2'"=="(" {
			local estcmd `1'
		}
	}
	else {  //  Is the first token an estimation command?
		capture confirm numeric variable `1'
		if _rc==0 {
			di as err "First word in the command line should be one of Stata's"  ///
			_n "estimation commands that is linear in the parameters."  ///
			_n "Examples include {help reg}, {help sureg}, {help frontier}, etc.."  ///
			_n "Here the first word in the command line is the variable: " as res "`1'"
			exit 198
		}
		else {
			local estcmd `1'
			macro shift
			local cmdline `*'
		}
	}

	//	Now consider the command line without the estimation command or the
	//	equation binding prefixes.
	tokenize `"`cmdline'"', parse(" :")

	if "`2'"==":" {
		local eqname `1'
		local depvar `3'
		local cmdline = substr(`"`cmdline'"',strpos(`"`cmdline'"',":")+1,.)
	}
	else {
		local eqname `1'
		local depvar `1'
	}

	capture confirm numeric variable `depvar'
		if _rc~=0 {
			di as err _n "Unable to find the dependent variable in the command line" ///
				_n "Here it is: -" as res "`depvar'" as err "-"
			di as err _n "which has been extracted from the command line:" ///
				_n as res `"`origcmdline'"'
			exit 198
		}

	//	truncate the command line before the first parenthesis
	local firstparen = min(strpos(`"`cmdline'"',"("),strpos(`"`cmdline'"',")"))
	if `firstparen' >0 & `firstparen' < . {
		local cmdline = substr(`"`cmdline'"',1,`firstparen'-1)
	}

	return local cmdline `cmdline'
	return local origcmdline `origcmdline'
	return local estcmd `estcmd'
	return local eqname `eqname'
	return local depvar `depvar'

*	Version information to program -cleancmdline-
*	Version 1.0 13July2016
*	Version 1.1 13July2016	Only change is to edit the comment in line 20
*	Version 1.2 19Aug2016		Clean simple command lines like: "reg y x1 x2 x1*x2"
end /* End of program cleancmdline */
*/

*	Based on -glelasticity.ado- from 6/9/2012
*	14Nov2016	Version 1.1  Add call to -cleancmdline-
*	21Jul2017	Version 1.2  Allow e(cmdline) to substitute for the option cmdline(string)
*	8Aug2017	Version 1.3  Add error trap if the -varlist- variables are not in the command line.
*				Add -omitshare- option to replace a share with 1 - sum of other shares.
*				(not yet implemented)
*	4May2018  Version 1.4  Comment out the internal version of -cleancmdline-