*! version 1.2.2 27jul2009

/*
*! 12 March09: made it possible for varlist for time varying covariates to be greater than 244 characters.
*! PR 09mar09: added e(aic) and e(bic)
*! stpm2 now reports same likelihood as stpm and other parametric models
*! PR 16apr08: -verbose- option added;
*! Added -showcons- option as constraints are not shown by default
*! 11/12/2008 Changed to using rcsgen for spline functions.
*! 23/4/2009 correct waldtest - this is no longer reported
*! 27/4/2009 changed e(aic) and e(bic) to e(AIC) and e(BIC) so can be used with estimates table
*/

program stpm2, eclass byable(onecall)
	version 10.0

	if strpos("`0'","oldstpm") >0 {
		local 0:subinstr local 0 "oldstpm" ""
		stpm `0'
		exit
	}
	if _by() {
		local by "by `_byvars'`_byrc0':"
	}
	if replay() {
		syntax  [, DF(string) KNOTS(numlist ascending) BKNOTS(numlist ascending min=2 max=2) *]
		if "`df'`knots'`bknots'" != "" {
			`by' Estimate `0'
		}
		else {
			if "`e(cmd)'" != "stpm2" {
				error 301
			}
			if _by() {
				error 190
				}
			Replay `0'
		}
		exit
	}
	`by' Estimate `0'
	ereturn local cmdline `"stpm2 `0'"'
end

program Estimate, eclass byable(recall)
	st_is 2 analysis
	syntax  [varlist(default=empty)] [if] [in] ///
	[, DF(string) TVC(varlist) DFTvc(string) KNOTS(numlist ascending) KNOTSTvc(string) ///
		BKnots(numlist ascending min=2 max=2) KNSCALE(string) noORTHog SCale(string) noCONStant ///
		INITTheta(real 1) CONSTheta(string) EForm ALLEQ KEEPCons BHAZard(varname) ///
		LINinit STratify(varlist) THeta(string) OFFset(varname) ///
		/* !! PR */ STPMDF(int 0) VERBose SHOWCons ///
		ALL RMAT ] ///
	[                               ///
	noLOg                           /// -ml model- options
	noLRTEST                        ///
	Level(integer `c(level)')       /// -Replay- option
	*                               /// -mlopts- options
	]

// !! PR - note that stpmdf() overrides df() if both specified.
if `stpmdf'>0 local df `stpmdf'

/* Check rcsgen is installed */
	capture which rcsgen
	if _rc >0 {
		display in yellow "You need to install the command rcsgen. This can be installed using,"
		display in yellow ". {stata ssc install rcsgen}"
		exit  198
	}


/* Temporary variables */
	tempvar Z xb lnt lnt0 coxindex S Sadj cons touse2 touse_t0 cons
	tempname initmat Rinv_bh R_bh rmatrix

/* Marksample and mlopts */
	marksample touse
	qui replace `touse' = 0  if _st==0
	mlopts mlopts, `options'
	local extra_constraints `s(constraints)'

/* collinear option not allowed */
	if `"`s(collinear)'"' != "" {
		di as err "option collinear not allowed"
		exit 198
	}

/* use of all option to calculate spline variables out of sample */
	if `"all"' != "" {
		gen `touse2' = 1
	}
	else {
		gen `touse2' = `touse'
	}

/* Drop previous created _rcs and _d_rcs variables */
	capture drop _rcs*
	capture drop _d_rcs*
	capture drop _s0_rcs*

/* Check time origin for delayed entry models */
	local del_entry = 0
	qui summ _t0 if `touse' , meanonly
	if r(max)>0 {
		display in green  "note: delayed entry models are being fitted"
		local del_entry = 1
	}

/* Orthogonal retricted cubic splines */
	if "`orthog'"=="noorthog" {
		local orthog
	}
	else {
		local orthog orthog
	}

/* generate log time */
	qui gen `lnt' = ln(_t) if `touse2'

/* Ignore options associated with time-dependent effects if specified without the tvc option */
	if "`tvc'" == "" {
		foreach opt in dftvc knotstvc {
			if "``opt''" != "" {
				display as txt _n "[`opt'() used without specifying tvc(), option ignored]"
				local `opt'
			}
		}
	}

/* use no orthogonalization if rmat option specified */
/* add checks for no tvc etc */
	if "`rmat'" != "" {
		if "`tvc'" != "" {
			display as error "tvc option not available when using rmat option"
			exit 198
		}
		local orthog
		matrix `rmatrix' = e(R_bh)
		local rmatrixopt rmatrix(`rmatrix')
	}

/* Old stpm options */
/* Stratify */
	if "`stratify'" != "" {
		if "`tvc'" != "" {
			display as error "You can not specify both the stratify and tvc options"
			exit 198
		}
		local tvc `stratify'
		local dftvc `df'
	}

/* if bhazard option not specifed make it a column of zeros */
	if "`bhazard'" != "" {
		if `touse' & missing(`bhazard') == 1 {
			display as err "baseline hazard contains missing values"
			exit
		}
		local rs _rs
	}

/* set up spline variables */
	tokenize `knots'
	local nbhknots : word count `knots'

/* Only one of df and knots can be specified */
	if "`df'" != "" & `nbhknots'>0 {
		display as error "Only one of DF OR KNOTS can be specified"
		exit
	}

/* df must be specified */
	if `nbhknots' == 0 & "`df'" == "" {
		display as error "Use of either the df or knots option is compulsory"
		exit 198
	}

/* df for time-dependent variables */

	if "`tvc'"  != "" {
		if "`dftvc'" == "" & "`knotstvc'" == "" {
			display as error "The dftvc option is compulsory if you use the tvc option"
			exit 198
		}
		local ntvcdf: word count `dftvc'
		tokenize "`dftvc'"
		forvalues i = 1/`ntvcdf' {
			local tvcdflist`i' ``i''
			local wordtvcdflist: word count tvcdflist`i'
			if `wordtvcdflist' == 1 {
				local defaulttvcdf `tvcdflist`i''
			}
		}

		foreach tvcvar in  `tvc' {
			local `tvcvar'_df `defaulttvcdf'
		}

		forvalues i = 1/`ntvcdf' {
			tokenize "`tvcdflist`i''", parse(":")
			local `1'_df `3'
		}
	}

/* knotstvc option */
	if "`knotstvc'" != "" {
		if "`dftvc'" != "" {
			display as error "You can not specify the dftvc and knotstvc options"
			exit 198
		}
		tokenize `knotstvc'
		while "`2'"!="" {
			cap confirm var `1'
			if _rc == 0 {
				if `"`: list posof `"`1'"' in tvc'"' == "0" {
					display as error "`1' is not listed in the tvc option"
					exit 198
				}
				local tmptvc `1'
				local `tmptvc'_df 1
			}
			cap confirm num `2'
			if _rc == 0 {
				local tvcknots_`tmptvc'_user `tvcknots_`tmptvc'_user' `2'
				local `tmptvc'_df = ``tmptvc'_df' + 1
			}
			else {
				cap confirm var `2'
				if _rc {
					display as error "`2' is not a variable"
					exit 198
				}
			}
			macro shift 1
		}
	}

/* Check scale options specified */
	if "`scale'" =="" {
		display as error "The scale must be specified"
		exit
	}

/* define scale */
	if substr("`scale'", 1, 1)=="h" {
		local scale "hazard"
	}
	else if substr("`scale'", 1, 1)=="o" {
		local scale "odds"
	}
	else if substr("`scale'", 1, 1)=="n" {
		local scale "normal"
	}
	else if substr("`scale'", 1, 1)=="t" {
		local scale "theta"
	}
	else {
		display as error "The scale must be specified as either hazard, odds, normal or theta"
		exit
	}

/* Ensure only certain options used with scale(theta) */
	if "`scale'" != "theta" {
		foreach thetaopt in constheta {
			if "``thetaopt''" != "" {
				display as err "`thetaopt' should only be used with the scale(theta) option"
				exit 198
			}
		}
	}

	if "`scale'" == "odds" & "`theta'" != "" {
		local scale theta
		if "`theta'" != "est" {
			local constheta `theta'
		}
	}

/* knots given on which scale */
	if "`knscale'" == "" {
		local knscale time
	}

/* Boundary Knots */
	if "`bknots'" == "" {
		summ `lnt' if `touse' & _d == 1, meanonly
		local lowerknot `r(min)'
		local upperknot `r(max)'
	}
	else if substr("`knscale'",1,1) == "t" {
		local lowerknot = ln(real(word("`bknots'",1)))
		local upperknot = ln(real(word("`bknots'",2)))
	}
	else if substr("`knscale'",1,1) == "l" {
		local lowerknot = word("`bknots'",1)
		local upperknot = word("`bknots'",2)
	}
	else if substr("`knscale'",1,1) == "c" {
		qui centile `lnt' if `touse' & _d==1, centile(`bknots')
		local lowerknot = `r(c_1)'
		local upperknot = `r(c_2)'
	}

	/* Knot placement for baseline hazard */
	if `nbhknots' == 0 {
		if `df' == 1 {
			qui rcsgen `lnt' if `touse2', gen(_rcs) dgen(_d_rcs) `orthog' `rmatrixopt'
			if "`orthog'" != "" {
				matrix `R_bh' =  r(R)
			}
		}
		else if `df' == 2 {
			qui centile `lnt' if `touse' & _d==1, centile(50)
			local bhknots  `lowerknot' `r(c_1)' `upperknot'
		}
		else if `df' == 3 {
			qui centile `lnt' if `touse' & _d==1, centile(33 67)
			local bhknots  `lowerknot' `r(c_1)' `r(c_2)' `upperknot'
		}
		else if `df' == 4 {
			qui centile `lnt' if `touse' & _d==1, centile(25 50 75)
			local bhknots  `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `upperknot'
		}
		else if `df' == 5 {
			qui centile `lnt' if `touse' & _d==1, centile(20 40 60 80)
			local bhknots  `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `upperknot'
		}
		else if `df' == 6 {
			qui centile `lnt' if `touse' & _d==1, centile(17 33 50 67 83)
			local bhknots  `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `upperknot'
		}
		else if `df' == 7 {
			qui centile `lnt' if `touse' & _d==1, centile(14 29 43 57 71 86)
			local bhknots `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `upperknot'
		}
		else if `df' == 8 {
			qui centile `lnt' if `touse' & _d==1, centile(12.5 25 37.5 50 62.5 75 87.5)
			local bhknots `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `r(c_7)' `upperknot'
		}
		else if `df' == 9 {
			qui centile `lnt' if `touse' & _d==1, centile(11.1 22.2 33.3 44.4 55.6 66.7 77.8 88.9)
			local bhknots `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `r(c_7)' `r(c_8)' `upperknot'
		}
		else if `df' == 10 {
			qui centile `lnt' if `touse' & _d==1, centile(10 20 30 40 50 60 70 80 90)
			local bhknots `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `r(c_7)' `r(c_8)' `r(c_9)' `upperknot'
		}
		else {
			display as error "DF must be between 1 and 10"
			exit
		}
	}


/* knot placement for time-varying covariates */
	if "`tvc'" != "" {
		foreach tvcvar in  `tvc' {
			if "`tvcknots_`tvcvar'_user'" == "" {
				if ``tvcvar'_df' == 1 {
					qui rcsgen `lnt' if `touse2', gen(_rcs_`tvcvar') dgen(_d_rcs_`tvcvar') `orthog'
					if "`orthog'" != "" {
						tempname R_`tvcvar' Rinv_`tvcvar'
						matrix `R_`tvcvar'' =  r(R)
					}
				}
				else if ``tvcvar'_df'==2 {
					qui centile `lnt' if `touse' & _d==1, centile(50)
					local tvcknots_`tvcvar'  `lowerknot' `r(c_1)' `upperknot'
				}
				else if ``tvcvar'_df'==3 {
					qui centile `lnt' if `touse' & _d==1, centile(33 67)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `upperknot'
					}
				else if ``tvcvar'_df'==4 {
					qui centile `lnt' if `touse' & _d==1, centile(25 50 75)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `upperknot'
				}
				else if ``tvcvar'_df'==5 {
					qui centile `lnt' if `touse' & _d==1, centile(20 40 60 80)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `upperknot'
				}
				else if ``tvcvar'_df'==6 {
					qui centile `lnt' if `touse' & _d==1, centile(17 33 50 67 83)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `upperknot'
				}
				else if ``tvcvar'_df'==7 {
					qui centile `lnt' if `touse' & _d==1, centile(14 29 43 57 71 86)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `upperknot'
				}
				else if ``tvcvar'_df'==8 {
					qui centile `lnt' if `touse' & _d==1, centile(12.5 25 37.5 50 62.5 75 87.5)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `r(c_7)' `upperknot'
				}
				else if ``tvcvar'_df'==9 {
					qui centile `lnt' if `touse' & _d==1, centile(11.1 22.2 33.3 44.4 55.6 66.7 77.8 88.9)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `r(c_7)' `r(c_8)' `upperknot'
				}
				else if ``tvcvar'_df'==10 {
					qui centile `lnt' if `touse' & _d==1, centile(10 20 30 40 50 60 70 80 90)
					local tvcknots_`tvcvar' `lowerknot' `r(c_1)' `r(c_2)' `r(c_3)' `r(c_4)' `r(c_5)' `r(c_6)' `r(c_7)' `r(c_8)' `r(c_9)' `upperknot'
				}
				else {
					display as error "DF for time-dependent effects must be between 1 and 10"
					exit
				}
			}
		}
	}

/* Generate splines for baseline hazard */
	/* !! PR */ if "`verbose'"=="verbose" display as txt "Generating Spline Variables"
	if `nbhknots'>0 {
		local bhknots `lowerknot'

		forvalues i=1/`nbhknots' {
			if substr("`knscale'",1,1) == "t" {
				local addknot = ln(real(word("`knots'",`i')))
			}
			else if substr("`knscale'",1,1) == "l" {
				local addknot = word("`knots'",`i')
			}
			else if substr("`knscale'",1,1) == "c" {
				local tmpknot = word("`knots'",`i')
				qui centile `lnt' if `touse' & _d==1, centile(`tmpknot')
				local addknot = `r(c_1)'
			}
			local bhknots `bhknots' `addknot'
		}
		local bhknots `bhknots' `upperknot'
	}

	if "`df'" != "1" {
		qui rcsgen `lnt' if `touse2', knots(`bhknots') gen(_rcs) dgen(_d_rcs) `orthog'  `rmatrixopt'
		if "`orthog'" != "" {
			matrix `R_bh' = r(R)
		}
	}

/* Generate splines for time-dependent effects */
	if "`tvc'" != "" {
		foreach tvcvar in  `tvc' {
			if ``tvcvar'_df' != 1 {
				if "`tvcknots_`tvcvar'_user'" != "" {
					local n_`tvcvar': word count `tvcknots_`tvcvar'_user'
					local tvcknots_`tvcvar' `lowerknot'

					forvalues i=1/`n_`tvcvar'' {
						if substr("`knscale'",1,1) == "t" {
							local addknot = ln(real(word("`tvcknots_`tvcvar'_user'",`i')))
						}
						else if substr("`knscale'",1,1) == "l" {
							local addknot = word("`tvcknots_`tvcvar'_user'",`i')
						}
						else if substr("`knscale'",1,1) == "c" {
							local tmpknot = word("`tvcknots_`tvcvar'_user'",`i')
							qui centile `lnt' if `touse' & _d==1, centile(`tmpknot')
							local addknot = `r(c_1)'
						}
						local tvcknots_`tvcvar' `tvcknots_`tvcvar'' `addknot'
					}
					local tvcknots_`tvcvar' `tvcknots_`tvcvar'' `upperknot'
 				}
				qui rcsgen `lnt' if `touse2', knots(`tvcknots_`tvcvar'') gen(_rcs_`tvcvar') dgen(_d_rcs_`tvcvar')  `orthog'
				if "`orthog'" != "" {
					tempname R_`tvcvar' Rinv_`tvcvar'
					matrix `R_`tvcvar'' = r(R)
				}
			}
		}
	}

	/* Added so R matrix is returned when using rmat option */
	if "`rmat'" != "" {
			local orthog orthog
			matrix `R_bh' = `rmatrix'
	}



/* Generate splines for delayed entry */
	if `del_entry' == 1 {
		qui gen `lnt0' = ln(_t0) if `touse' & _t0>0
		if "`df'" == "1" {
			qui rcsgen `lnt0' if `touse2' & _t0>0, gen(_s0_rcs1)
		}
		else if "`df'" != "1" {
			qui rcsgen `lnt0' if `touse2' & _t0>0, knots(`bhknots') gen(_s0_rcs)
		}
		foreach tvcvar in  `tvc' {
			if ``tvcvar'_df' == 1 {
				qui rcsgen `lnt0' if `touse2' & _t0>0,  gen(_s0_rcs_`tvcvar')
			}
			else if ``tvcvar'_df' != 1 {
				qui rcsgen `lnt0' if `touse2' & _t0>0, knots(`tvcknots_`tvcvar'') gen(_s0_rcs_`tvcvar')
			}
		}
	}

	local nk : word count `bhknots'
	if "`df'" == "1" {
		local df = 1
	}
	else {
		local df = `nk' - 1
	}
/* create list of spline terms and their derivatives for use when orthogonalizing and in model equations */
	forvalues i = 1/`df' {
		local rcsterms_base "`rcsterms_base' _rcs`i'"
		local drcsterms_base "`drcsterms_base' _d_rcs`i'"
	}

	local rcsterms `rcsterms_base'
	local drcsterms `drcsterms_base'
	if "`tvc'" != "" {
		foreach tvcvar in  `tvc' {
			forvalues i = 1/``tvcvar'_df' {
				local rcsterms_`tvcvar' "`rcsterms_`tvcvar'' _rcs_`tvcvar'`i'"
				local drcsterms_`tvcvar' "`drcsterms_`tvcvar'' _d_rcs_`tvcvar'`i'"
				local rcsterms "`rcsterms' _rcs_`tvcvar'`i'"
				local drcsterms "`drcsterms' _d_rcs_`tvcvar'`i'"
			}
		}
	}

/* Orthogonalisation of delayed entry terms */
	if "`orthog'" != "" {
		qui gen `touse_t0' = `touse2'*(_t0>0)
		if `del_entry' == 1 {
			qui gen `cons' = 1 if `touse2' & _t0>0
			matrix `Rinv_bh' = inv(`R_bh')
			local s0_rcsterms : subinstr local rcsterms_base "_rcs" "_s0_rcs", all

			mata st_store(.,tokens(st_local("s0_rcsterms")),"`touse_t0'",(st_data(.,(tokens(st_local("s0_rcsterms")),"`cons'"),"`touse_t0'")*st_matrix("`Rinv_bh'"))[,1..`df'])

			if "`tvc'" != "" {
				foreach tvcvar in  `tvc' {
					matrix `Rinv_`tvcvar'' = inv(`R_`tvcvar'')
					local s0_rcsterms_`tvcvar' : subinstr local rcsterms_`tvcvar' "_rcs" "_s0_rcs", all
					mata st_store(.,tokens(st_local("s0_rcsterms_`tvcvar'")),"`touse_t0'",(st_data(.,(tokens(st_local("s0_rcsterms_`tvcvar'")),"`cons'"),"`touse_t0'")*st_matrix("`Rinv_`tvcvar''"))[,1..``tvcvar'_df'])
				}
			}
		}
	}

/* multiply time-dependent _rcs and _drcs terms by time-dependent covariates */
	if "`tvc'" != "" {
		foreach tvcvar in  `tvc' {
			forvalues i = 1/``tvcvar'_df' {
				qui replace _rcs_`tvcvar'`i' = _rcs_`tvcvar'`i'*`tvcvar' if `touse2'
				qui replace _d_rcs_`tvcvar'`i' = _d_rcs_`tvcvar'`i'*`tvcvar' if `touse2'
				if `del_entry' == 1 {
					qui replace _s0_rcs_`tvcvar'`i' = _s0_rcs_`tvcvar'`i'*`tvcvar' if `touse2' & _t0>0
				}
			}
		}
	}

/* replace missing values for delayed entry with -99 as ml will omit these cases. -99 is not included in the likelihood calculation */
	if `del_entry' == 1 {
		forvalues i = 1/`df' {
			qui replace _s0_rcs`i' = -99 if `touse2' & _t0 == 0
		}
		foreach tvcvar in `tvc' {
			forvalues i = 1/``tvcvar'_df' {
				qui replace _s0_rcs_`tvcvar'`i' = -99 if `touse2' & _t0 == 0
			}
		}
	}

/* variable labels */
	forvalues i = 1/`df' {
		label var _rcs`i' "restricted cubic spline `i'"
		label var _d_rcs`i' "derivative of restricted cubic spline `i'"
		if `del_entry' == 1 {
			label var _s0_rcs`i' "restricted cubic spline `i' (delayed entry)"
		}
	}

	if "`tvc'" != "" {
		foreach tvcvar in  `tvc' {
			forvalues i = 1/``tvcvar'_df' {
				label var _rcs_`tvcvar'`i' "restricted cubic spline `i' for tvc `tvcvar'"
				label var _d_rcs_`tvcvar'`i' "derivative of restricted cubic spline `i' for tvc `tvcvar'"
				if `del_entry' == 1 {
					label var _s0_rcs_`tvcvar'`i' "restricted cubic spline `i' for tvc `tvcvar' (delayed entry)"
				}
			}
		}
	}

/* Remove collinearity. */
	if "`varlist'" != "" {
		local colvarlist (`varlist')
	}
	_rmcollright (`rcsterms') `colvarlist' if `touse', `constant'
	local varlist `r(block2)'

/* Define Offset */
	if "`offset'" != "" {
		local offopt offset(`offset')
		local addoff +`offset'
	}

/* initial values fit a Cox model with (linear time-dependent covariates) */
/* Taken from Patrick Roystons stpm code */

	/* !! PR */ if "`verbose'"=="verbose" display as txt "Obtaining Initial Values"
	if "`lininit'" == "" {
		if "`tvc'" != "" {
			local tvcterms tvc(`tvc') texp(ln(_t))
		}
		qui stcox `varlist' if `touse', estimate
		qui predict `coxindex' if `touse', xb
		qui sum `coxindex' if `touse'
		qui replace `coxindex'=`coxindex'-r(mean) if `touse'
		qui stcox `coxindex' if `touse', basechazard(`S')
		if "`bhazard'" != "" {
			qui replace `S' = `S' - 0.1*`bhazard'*_t if `touse'
		}
		qui replace `S'=exp(-`S') if `touse'
		qui predict double `Sadj' if `touse', hr
		qui replace `Sadj'=`S'^`Sadj' if `touse'
		if "`scale'" == "hazard" {
			qui gen double `Z' = ln(-ln(`Sadj')) `addoff' if `touse'
		}
		else if "`scale'" == "odds" {
			qui gen double `Z' = ln((1-`Sadj')/`Sadj')  `addoff'  if `touse'
		}
		else if "`scale'" == "normal" {
			qui count if `touse'
			local nobs=r(N)
			qui gen double `Z' = invnormal((`nobs'*(1-`Sadj')-3/8)/(`nobs'+1/4))  `addoff' if `touse'
		}
		else if "`scale'" == "theta" {
			qui gen double `Z' = ln((`Sadj'^(-`inittheta') - 1)/(`inittheta'))  `addoff' if `touse'
		}
		qui regress `Z' `varlist' `rcsterms'  if `touse' & _d == 1 , `constant'
		matrix `initmat' = e(b)

	/* initial values for theta */
		if "`scale'" == "theta" {
			local thetaeq (ln_theta:)
			if "`constheta'"  == "" {
				local lntheta = ln(`inittheta')
				matrix `initmat' = `initmat' , `lntheta'
			}
			else {
				local lntheta = ln(`constheta')
				matrix `initmat' = `initmat' , `lntheta'
			}
		}

		local ncopy : word count `rcsterms'
		local nstart : word count `varlist'
		local nstart = `nstart' + 1
		local ncopy = `nstart' + `ncopy' -1
		matrix `initmat' = `initmat', `initmat'[1,`nstart'..`ncopy']
	}

/* Fit linear term to log(time) for initial values. */
	else {
		if inlist("`scale'","hazard","odds","normal") {
			local initrcslist _rcs1
			local initdrcslist _d_rcs1
			constraint free
			constraint `r(free)' [xb][_rcs1] = [dxb][_d_rcs1]
			local initconslist `r(free)'
			if "`tvc'" != "" {
				foreach tvcvar in `tvc' {
					local initrcslist `initrcslist' _rcs_`tvcvar'1
					local initdrcslist `initdrcslist' _d_rcs_`tvcvar'1
					constraint free
					constraint `r(free)' [xb][_rcs_`tvcvar'1] = [dxb][_d_rcs_`tvcvar'1]
					local initconslist `initconslist' `r(free)'
				}
			}
			if `del_entry' == 1 {
				local xb0 `"(xb0: `varlist' `:subinstr local initrcslist "_rcs" "_s0_rcs",all' ,`constant' `offopt')"'

				if "`constant'" == "" {
					local addconstant _cons
				}
				foreach var in `initrcslist' `varlist' `addconstant' {
					constraint free
					if substr("`var'",1,4) == "_rcs" {
						constraint `r(free)' [xb][`var'] = [xb0][_s0`var']
					}
					else {
						constraint `r(free)' [xb][`var'] = [xb0][`var']
					}
					local initconslist `initconslist' `r(free)'
				}
			}
			/* !! PR */ if "`verbose'"=="verbose" display as txt "Obtaining Initial Values"

			qui ml model d1 stpm2_ml_`scale'`rs' ///
					(xb: `bhazard' =  `varlist' `initrcslist', `constant' `offopt') ///
					`thetaeq' ///
					(dxb: `initdrcslist', nocons)  ///
					`xb0' ///
					if `touse', ///
					`mlopts' ///
					`collinear' ///
					constraints(`initconslist') ///
					search(norescale) ///
					maximize

			display in green "Initial Values Obtained"
			matrix `initmat' = e(b)
			constraint drop `initconslist'
		}
	}


/* Define constraints */
	local conslist
	local fplist
	local dfplist

/* constraints for theta if option constheta(#) is specified */
	if "`scale'" == "theta" & "`constheta'" !="" {
		constraint free
		constraint `r(free)' [ln_theta][_cons] = `constheta'
		local conslist `conslist' `r(free)'
	}

/* constraints for baseline */
	forvalues k = 1/`df' {
		constraint free
		constraint `r(free)' [xb][_rcs`k'] = [dxb][_d_rcs`k']
		local conslist `conslist' `r(free)'
	}

/* constraints for time-dependent effects */
	if "`tvc'" != "" {
		foreach tvcvar in  `tvc' {
			forvalues k = 1/``tvcvar'_df' {
				constraint free
				constraint `r(free)' [xb][_rcs_`tvcvar'`k'] = [dxb][_d_rcs_`tvcvar'`k']
				local conslist `conslist' `r(free)'
			}
		}
	}

/* constraints for extra equation if delayed entry models are being fitted */
	if `del_entry' == 1 {
		local xb0: subinstr local rcsterms "_rcs" "_s0_rcs", all

		local xb0 (xb0: `varlist' `xb0', `constant' `offopt')

		local xbvarlist `varlist' `rcsterms'
		if "`constant'" == "" {
			local xbvarlist `xbvarlist' _cons
		}
		foreach term in `xbvarlist' {
			constraint free
			if substr("`term'",1,4) == "_rcs" {
				local addterm = "_s0" + "`term'"
			}
			else {
				local addterm `term'
			}
			constraint free
			constraint `r(free)' [xb][`term'] = [xb0][`addterm']
			local conslist `conslist' `r(free)'
		}

		if "`lininit'" == "" {
			local nxbterms: word count `xbvarlist'
			matrix `initmat' = `initmat', `initmat'[1,1..`nxbterms']
		}
	}

/* If further constraints are listed stpm2 then remove this from mlopts and add to conslist */
	if "`extra_constraints'" != "" {
*		local mlopts = subinstr("`mlopts'","constraints(`extra_constraints')","",1)
		local mlopts : subinstr local mlopts "constraints(`extra_constraints')" "",word
		local dropconslist `conslist'
		local conslist `conslist' `extra_constraints'
	}

/* Fit Model */
	if "`lininit'" == "" {
		local initopt "init(`initmat',copy)"
	}
	else {
		local initopt "init(`initmat')"
	}

	/* !! PR */ if "`verbose'"=="verbose" display as txt "Starting to Fit Model"
	if inlist("`scale'","hazard","odds","normal") {
		local mlmethod d2
	}
	else {
		local mlmethod lf
	}
	if "`scale'" == "normal" & "`rs'" != "" {
		local mlmethod lf
	}


	ml model `mlmethod' stpm2_ml_`scale'`rs' ///
		(xb: `bhazard' = `varlist' `rcsterms', `constant' `offopt') ///
		`thetaeq' ///
		(dxb: `drcsterms', nocons)  ///
		`xb0' ///
		if `touse', ///
		`mlopts' ///
		collinear ///
		constraints(`conslist') ///
		`initopt'  ///
		search(off) ///
		waldtest(0) ///
		`log' ///
		maximize


	ereturn local predict stpm2_pred
	ereturn local cmd stpm2
	ereturn local depvar "_d _t"
	ereturn local varlist `varlist'
	ereturn local tvc `tvc'
	ereturn local constant `noconstant'
	local exp_lowerknot = exp(`lowerknot')
	local exp_upperknot = exp(`upperknot')
	ereturn local boundary_knots "`exp_lowerknot' `exp_upperknot'"
	if `df' >1 {
		forvalues i = 2/`df' {
			local addknot = exp(real(word("`bhknots'",`i')))
			local exp_bhknots `exp_bhknots' `addknot'
		}
		ereturn local bhknots `exp_bhknots'
	}
	ereturn local ln_bhknots `bhknots'
	ereturn local rcsterms_base `rcsterms_base'
	ereturn local drcsterms_base `drcsterms_base'
	ereturn scalar dfbase = `df'
	ereturn scalar nxbterms = e(rank) - ("`scale'" == "theta")
	foreach tvcvar in  `tvc' {
		ereturn scalar df_`tvcvar' = ``tvcvar'_df'
		ereturn local rcsterms_`tvcvar' `rcsterms_`tvcvar''
		ereturn local drcsterms_`tvcvar' `drcsterms_`tvcvar''
		if ``tvcvar'_df'>1 {
			local exp_knots
			forvalues i = 2/``tvcvar'_df' {
				local addknot = exp(real(word("`tvcknots_`tvcvar''",`i')))
				local exp_knots `exp_knots' `addknot'
			}
			ereturn local tvcknots_`tvcvar' `exp_knots'
			ereturn local ln_tvcknots_`tvcvar' `tvcknots_`tvcvar''
		}
		if "`orthog'" != "" {
			ereturn matrix R_`tvcvar' = `R_`tvcvar''
		}
	}
	if "`orthog'" != "" {
		ereturn matrix R_bh = `R_bh'
	}
	ereturn local noconstant `constant'
	ereturn local scale `scale'
	ereturn local orthog  `orthog'
	ereturn local bhazard `bhazard'
	ereturn scalar del_entry = `del_entry'
	ereturn scalar dev = -2*e(ll)
	ereturn scalar AIC = -2*e(ll) + 2 * e(rank)
	qui count if `touse' == 1 & _d == 1
	ereturn scalar BIC = -2*e(ll) + ln(r(N)) * e(rank)

	if "`keepcons'" == "" {
		constraint drop `dropconslist'
	}
	Replay, level(`level') `alleq' `eform' `showcons'
end

program Replay
	syntax [, EFORM ALLEQ SHOWCons Level(int `c(level)') ]
	if "`alleq'" == "" {
		local neq neq(1)
		if "`e(scale)'" == "theta" {
			local neq neq(2)
		}
	}

/* Don't show constraints unless cnsreport option is used */
	if "`showcons'" == "" {
		local showcons nocnsreport
	}
	else {
		local showcons
	}

	ml display, `eform' `neq' `showcons' level(`level')
end