*! version 1.23  (TSJ-2: st0008)

*! Date        : 25 Sep 2001
*! Version     : 1.23
*! Author      : Adrian Mander
*! Email       : adrian.mander@mrc-bsu.cam.ac.uk
*! Description : Quantitative trait haplotype analysis

/* 2/3/01 bug fix in haplo expansion for haplotypes */

program define qhapipf, rclass
version 7.0
syntax [varlist] [using/] [if] ,[ IPF(string) REGress(string) DOM(string) START DISplay EXPect KNOWN PHASE(varname) ACC(real 0.001) IPFACC(real 0.000001) DEBUG(integer 0) NOLOG MODEL(integer 0) LRTEST(numlist) RARE(real 0) CONVARS(string) CONFILE(string) QUIET NOISE MV HAP(string) MVDEL LOGALL(integer 1) MENU QT(varname)]

di

/* Run the command from the menu system */

if "`menu'"~="" {
  cap _qmenu
  if _rc==3000 {
    di as text "Running $Qcommand..."
    $Qcommand
    exit
  }
  if _rc~=3000 {
    di in red "Command will not be run"
    exit
  }
}

if "`qt'"=="" {
  di in red "You must specify the Quantitative trait variable using the qt() option"
  exit(198)
}

tokenize "`varlist'"

matrix drop _all

cap which ipf
if _rc~=0 {
  di in red "YOU MUST INSTALL ipf.ado which was first introduced in STB55"
  di as error "This function performs the log-linear modelling"
  exit
}

tempfile origin temp
qui save "`origin'",replace

if "`if'"~="" { keep `if' }

global all_name = "`varlist'"
global nloc 0
global nsub= _N

/* Just a little check on the state of the dummy variable construction. */

if "`hap'"=="" {
  if "`quiet'"~="" {
    di "The program will attempt to select the reference haplotype"
    di "Use hap() to alter this e.g. hap(1.1.1) for 3 loci model"
  }
}

/***************************************************
 * Delete all lines with missing marker information
 * for each marker in the varlist
 ***************************************************/

  if "`mv'"~="" & "`known'"~="" { di as error "If you want to impute missing data then phase is not known for those people with missing typings!" }

  if "`mvdel'"~="" {
    di
    di as text "You have selected the deletion of missing lines"
    di "-----------------------------------------------"
    di as res "Variable [variable label] (#lines deleted)"
    while "`1'"~="" {
      qui count if `1'==.
      local lab : variable label `1'
      if "`lab'"~="" { di  _continue "`1' [`lab']", _col(17) " (" %4.0f `r(N)' ")" }
      else { di  _continue "`1'", _col(10) " (" %4.0f `r(N)' ")" }
      qui drop if `1'==.
      mac shift 1
      qui count if `1'==.
      local lab : variable label `1'
      if "`lab'"~="" { di  _col(10) "`1' [`lab'] (`r(N)')" }
      else { di  _col(10) "`1'  (`r(N)')" }
      qui drop if `1'==.
      mac shift 1
    }
  }
tokenize "`varlist'"

/***************************************************
 * warnings about missing data and the subsequent
 * deletion of the data
 ***************************************************/

qui summ `qt'
if `r(N)'~=_N {
  local nomiss = _N-`r(N)'
  di as text "Missing in the quantitative trait variable"
  di "------------------------------------------"
  di as text "There are `nomiss' missing values in `qt'"
  di as error "These lines will be deleted...."
  di
  qui drop if `qt'==.
}

/*********************************************
 * Pair the data from the varlist
 * and check that they are numeric
 *********************************************/

if "`quiet'"=="" {
  di
  di in green "Marker information"
  di in smcl "{dup 18:{c -}}"
}

local i 1
while "`1'"~="" {
   if "`2'"=="" { di in red "There must be paired data" }
   global nloc =$nloc+1
   local wc1=2*$nloc-1
   local wc2=`wc1'+1
   local root1: word `wc1' of $all_name
   local root2: word `wc2' of $all_name
   cap confirm string variable `root1'
   if _rc==0 {
     di "`root1' cannot be a string variable"
     exit(7)
   }
   cap confirm string variable `root2'
   if _rc==0 {
     di "`root2' cannot be a string variable"
     exit(7)
   }
   if "`quiet'"=="" {
     local lab1 : variable label `root1'
     local lab2 : variable label `root2'
     if "`lab1'"~="" & "`lab2'"~="" { di as res "Alleles for l$nloc are (`root1' , `root2') [`lab1' , `lab2']" }
     else { di as res "Alleles for l$nloc are (`root1' , `root2') " }
   }
   return local loci`i' = "`root1' `root2'"
   local i = `i'+1
mac shift 2
}

if "`quiet'"=="" {di}

local nloc = $nloc
if "`nloc'"~="1" {
  local haptext "Haplotype"
  local haptvar "Haplo"
}
else {
  local haptext "Allele"
  local haptvar "Allele"
}

/**********************************
 * Check out the constraint file
 **********************************/

tempfile temp

qui save "`temp'",replace

if "`confile'"~="" {
   di
   di as txt "NB the degrees of freedom are wrong when using the constraint files"
   if "`convars'"=="" { di as error "You must specify the convars() option when using constraint files" }
   use "`confile'",replace
   tokenize "`convars'"
   cap confirm variable Efreqold
   if _rc~=0 {
     cap confirm variable Ifreq
     if _rc~=0 {
       di in red "Constraints file doesnt contain Efreqold or Ifreq!"
       exit(198)
     }
     else { rename Ifreq Efreqold }
   }
   sort `convars'
   save "`confile'",replace

   while "`1'"~="" {
     mac shift 1
   }
}

/*********************************************
 * Make sure about including the ipf() option
 *********************************************/

  if "`ipf'"=="" {
    di in red "You must specify the loglinear model in the ipf() option "
    exit(198)
  }
  if "`regress'"=="" {
    di in red "You must specify the quantitative model in the regress() option "
    exit(198)
  }

use "`temp'",replace

/**********************************************************************
 * haplotyp expands the dataset into the phases
 * Takes the varlist and constructs the haplotypes
 * locus1 and locus2
 * For phase unknown locus1 and locus2 contain all possible haplotypes
 **********************************************************************
 * Additionally the user can specify that there are missing values
 * in the DNA typings with the MV option
 */

if "`known'"~="" & "`phase'"=="" { haplotyp, known `mv'}
if "`known'"=="" & "`phase'"==""{ haplotyp, `mv'}
if "`phase'"~="" { haplotyp,known phase(`phase') `mv'}


/* Haplotype dummy variables */

qui save "`temp'",replace

/*
 * If hap == all then when markers are multiallelic all factors are fitted
 * Else a single haplotype of interest is used as a reference factor.
 */

if "`hap'"=="all" {
  di as err "This has been disabled"
  exit(198)
  _mkdum2, add(`add')
}
else {
  if "`hap'"=="" { local hap "none" }
  if "`dom'"=="" { _mkdummy, hap(`hap') reg(`regress')}
}

local regnv=`r(nvars)'
local regmod "`r(model)'"
local regmoda "`r(modela)'"
local regmodb "`r(modelb)'"

use "`temp'",replace

qui {
drop `varlist'
compress
}

/***********************************************************
 * Start frequencies f1 - future thing to do is to
 * implement a weighting system on the start points
 *
 * Note that if a subject has been expanded by phase then
 * the start frequencies are spread evenly by default
 ***********************************************************/

tempvar f1 tef1
if "`start'"=="" {
   sort subject
   qui by subject: gen double `f1'=1/_N
}
else {
   sort subject
   qui gen double `f1'=uniform()
   qui by subject: gen double `tef1'= sum(`f1')
   qui by subject: replace `f1'= `f1'/`tef1'[_N]
   drop `tef1'
}

/*********************************************
 *   EM algorithm - We have equal weights for each genotype phase.
 * First we need to estimate haplotype frequencies given these weights.
 * Then use the hap frequencies in estimating P(H1)P(H2)
 * To calulate P(Y|H1,H2) use a regression model and put the fitted parameters
 * into the pdf to get the new weights
 *********************************************/

local cont 1
local it 0
local saveimp 0

      cap confirm new variable locus
      if _rc~=0 {
        di in red "Rename the variable locus"
        exit(111)
      }

/* Setup the temporary variables for the two regressions */

tempvar y1 y2 y1old y2old

while(`cont'==1) { /*Start of while loop */

   cap drop `pr' `prs'
   tempvar pr prs stupid plocus

   cap drop llh
   local it = `it'+1

/************************************************************
 *       # New estimate of haplotype relative frequencies
 ************************************************************/

   cap drop freq

      gen long `stupid' = _n /* this will preserve line numbers */

   /* Make one column of the haplotypes keeping all other variables as well */

      qui _stack locus1 locus2
      qui rename locus1 locus
      qui drop locus2

    /* generate individual loci variables - l1 l2 l3 ... put them in `vlist' */

      local i 1
      local vlist " "
      qui gen str40 `plocus' = locus
      while `i'<=$nloc {
         tempvar len len2
         qui gen `len' = index(`plocus',".")-1
         qui gen l`i'=real(substr(`plocus',1,`len'))
         if `i'==$nloc { qui replace l`i'=real(`plocus') }
         else { qui gen `len2' = index(`plocus',".")+1
         qui replace `plocus'=substr(`plocus',`len2',.) }
         drop `len'
         cap drop `len2'
         local vlist "`vlist' l`i'"
         local i=`i'+1
      }

      drop `plocus'

/************************************************************
 * Use the iterative proportional fitting algorithm and save
 * the expected frequencies in fit.dta
 * The variables present in the model are output into the
 * r(vlist) as this may contain more variables than loci
 ************************************************************/

tempfile fit
local file = substr("`fit'",1,index("`fit'",".")-1)

   if "`convars'"=="" {
     if "`noise'"=="" { qui ipf [fw=`f1'], exp fit(`ipf') save(`file') acc(`ipfacc') }
     else{ ipf [fw=`f1'], exp fit(`ipf') save(`file') acc(`ipfacc')  }
   }
   else {
      qui ipf [fw=`f1'],exp convars(`convars') confile(`confile') fit(`ipf') save(`file') acc(`ipfacc')
   }

   local df=r(df)
   local nparms=r(parms)
   local ncells=r(ncells)
   sort `r(vlist)'
   global ipflist = "`r(vlist)'"   /* should contain list of loci l1 l2 l3 ... */
   merge `r(vlist)' using `file'   /* merge in the new frequencies */

/******************************************************
 * Note now the haplotype probabilities are in prob
 *-----------------------------------------------------
 * Sometimes fit.dta has an unobserved line of  and we
 * have to reconstruct locus from l*
 ******************************************************/

local rvlist "`r(vlist)'"
qui count if locus==""

if `debug'>1 {
  l locus caco Efreq prob if locus==""
  di "`r(N)' loci missing"
}

if `r(N)' > 0 {
  tempvar temprep
  gen `temprep' = locus==""
  local i 1
  while `i'<=$nloc {
    qui replace locus = cond( locus=="", locus + string(l`i'), locus +"."+ string(l`i')) if `temprep'==1
    local i = `i'+1
  }
}

if `debug'>2 {
  l locus caco Efreq prob
}

/*******************************************************
 * Saving the expected Frequencies when the algorithm
 * converges
 *******************************************************/

  if `saveimp'==1 {
    tempfile imputef now
    qui save "`now'"
    sort `rvlist'
    qui by `rvlist': keep if _n==1
    qui save "`imputef'"
    use "`now'",clear
  }

/*************************************************************
 * Tidy up the datafile and retransform into wide format
 *************************************************************/

      drop `vlist' Efreq Ofreq _merge

      sort _stack `stupid'
      qui _ustack locus prob, by(_stack) val(1 2)
      drop _stack merg _merge

      drop `stupid'

/**************************************************************************
 * Perform the regression between the quantitative trait and
 * the haplotypes. Creating the dummy variables should be done once only!'
 *
 * Create two variables y1 and y2 that are perturbed y's then get ordered
 * genotype regression but only one variance estimate
 **************************************************************************/

  sort locus1 locus2 subject
  merge locus1 locus2 subject using dummy
  qui count if _merge~=3
  if `r(N)'>0 { di in red "merging with dummy has a problem" /*check the merge */
    exit 666
  }
  qui drop _merge
  tempvar lineno depvar

  tempvar tey n1 yhat
  tempvar swr sumw depvar

  qui reg `qt' `regmod' [pw=`f1'], nocons

/* estimates list */

  /* Calculate the standard error using the weights */

  qui predict double `yhat'
  local nop = `e(N)'-`e(df_r)'

/*******************************************************
 * Saving the yhats  when the algorithm
 * converges
 *******************************************************/

  if `saveimp'==1 {
    tempfile yhats now
    qui save "`now'"
    sort locus1 locus2
    qui by locus1 locus2: keep if _n==1
    keep locus1 locus2 `yhat'
    rename `yhat' mean
    qui save "`yhats'"
    use "`now'",clear
  }


/*
if `nop'~=`regnv'+1 {
  di as error "no of parms `nop' but should be ", (`regnv'+1)
  di as error "Reduce the complexity of the regression model"
  exit(666)
}
*/
  local regnop = `nop'

  /* WORK out the likelihood */

  sort subject

  /* calculate the variance estimate on the wide dataset. */

  qui gen double `swr' = sum( `f1'*(`yhat'-`qt')*(`yhat'-`qt') )
  qui gen double `sumw' = sum(`f1')

if (`sumw'[_N]-`nop')<=0 {
 di as red "more parameters than data"
 exit(2000)
}

/*******WARNING using the variance estimator without nop!!!!**************
 *  local rmse = sqrt( `swr'[_N]/(`sumw'[_N]-`nop') ) */

  local rmse = sqrt( `swr'[_N]/(`sumw'[_N]) )

/*summ `f1'
*di as text "`rmse' `llhd'"
*  di as error "ade2 `rmse' `e(N)' `e(df_r)'"
*noi l `swr' `sumw' */

  gen double proby  =  exp( -1/2*( (`qt'-`yhat')^2/((`rmse')^2) ) ) / (sqrt(2*asin(1)*2)*`rmse')

/* To do multiple regressions as a test.
 local extrareg "more"
 local i 1
 while "`extrareg'"=="more" & `i'<6 {
 qui gen double `pr' = prob1*prob2*proby
 sort subject
 qui by subject : gen double `prs'=sum(`pr')
 qui by subject : gen double llh = log(`prs'[_N])
 qui by subject : replace `pr' = `pr'/`prs'[_N]
 qui replace `f1' = `pr'
 qui by subject :gen double llhh= cond(_n==_N,llh[_n],0)
 qui replace llhh = sum(llhh)
 local llh = llhh[_N]
 drop llhh
 if "`nolog'"=="" { di as text "Iteration `it' loglhd = `llh'" }
 qui reg `qt' `regmod' [pw=`f1'], nocons
 drop `yhat' `swr' `sumw' proby `pr' llh `prs'
 qui predict double `yhat'
 local nop = `e(N)'-`e(df_r)'
 sort subject
 qui gen double `swr' = sum( `f1'*(`yhat'-`qt')*(`yhat'-`qt') )
 qui gen double `sumw' = sum(`f1')
 local rmse = sqrt( `swr'[_N]/(`sumw'[_N]-`nop') )
 gen double proby  =  exp( -1/2*( (`qt'-`yhat')^2/((`rmse')^2) ) ) / (sqrt(2*asin(1)*2)*`rmse')
 local i =`i'+1
 }
*/

  if `debug'>0 {
    di "The estimate of the standard deviation is `rmse'"
    gen double temp = exp( -1/2*( (`qt'-`yhat')^2/((`rmse')^2) ) )
    l temp proby prob1 locus1 locus2 `qt' `regmod' if _n<3, noobs
    drop temp
  }

/*************************************************************
 *     New Genotype probabilities (per phase and per subject)
 ************************************************************/

   qui gen double `pr' = prob1*prob2*proby

/*
  if "`logall'"~="" {
  if `logall'==1 {
 *    l subject `regmoda' `regmodb' `f1'
 *    l subject locus1 locus2 `qt' `yhat'
 *    l subject proby prob1 prob2 `pr'
  }
  if `logall'==1 {
 *      reg
 *      di "`rmse'"
  }
 }
*/

    drop prob1 prob2 `yhat'
    drop proby

/******************************************************************************
 *      Calculate log likelihood
 ******************************************************************************/

   cap confirm new variable llh llhh
   if _rc~= 0 { di in red "rename the variable below:"
      confirm new variable llh llhh
   }

      sort subject
      qui by subject : gen double `prs'=sum(`pr')
      qui by subject : gen double llh = log(`prs'[_N])
      qui by subject : replace `pr' = `pr'/`prs'[_N]

      qui by subject :gen double llhh= cond(_n==_N,llh[_n],0)

      qui replace llhh = sum(llhh)
      local llh = llhh[_N]
      drop llhh

      if "`nolog'"=="" { di as res "Iteration `it' loglhd = `llh'" }

/**************************************
 * Use the new weights for the ipf
 **************************************/

      qui replace `f1' = `pr'

/**************************************
 *       # Convergence test
 **************************************/

   if (`it'>1) {
     local cont = (`llh' - `lastllh')>`acc'
     if (`llh' < `lastllh') {
       local cont 1
       di as error "likelihood not increased in qhapipf"
       local problemllhd 1
     }
   }

if `saveimp'==0 {
  if `cont'==0 {
    local saveimp 1
    local cont 1
  }
}

local lastllh = `llh'

}  /*end of while loop */

/********************************************************************************
 *Display the last estimates of the regression
 ********************************************************************************/

if "`noise'"~="" { reg }

di
di as text "Regression Parameters"
di in smcl "{dup 21:{c -}}"

di as res "Residual standard deviation is " %8.4f `rmse'
di
di as text "Standard errors are calculated conditional on the weights"
di as text "  Var      Coef        SE            Parameter "
di in smcl "{c TLC}{dup 6:{c -}}{c TT}{dup 10:{c -}}{c TT}{dup 10:{c -}}{c TT}{dup 49:{c -}}{c TRC}"
local i 0
while `i'<=`regnv' {
  local lab: variable label _d`i'
  local regb = _b[_d`i']
  local regse = _se[_d`i']
  if `regb'~=0 & `regse'~=0 {
    di in smcl as text "{c |}", as res "_d`i'", as text "{col 8}{c |}",as res  %8.4f `regb', as text "{col 19}{c |}",as res %8.4f  `regse', as text "{col 30}{c |}", as res "`lab'", as text "{col 80}{c |}"
  }
  else {
    di in smcl as text "{c |}", as res "_d`i'", as text "{col 8}{c |}", as err "dropped", as text "{col 19}{c |}{col 30}{c |}{col 80}{c |}"
  }
local i = `i'+1
}
di in smcl "{c BLC}{dup 6:{c -}}{c BT}{dup 10:{c -}}{c BT}{dup 10:{c -}}{c BT}{dup 49:{c -}}{c BRC}"
di as text " ~= symbol represents dominance parameters"
di as text " &  symbol represents additive parameters."

_stack locus1 locus2 `pr' `pr'
rename locus1 locus

/********************************************************************************
 * In order to display the results I need the variables included
 * in the ipf model so that the expected frequencies are split
 * in groups of this as well
 ********************************************************************************/

     local i 1
     local vlist "$ipflist"
      while `i'<=$nloc {
         local length= length("l`i'")
         local ind = index("`vlist'","l`i'")
         if `ind'>0 { local vlist = substr("`vlist'",1,`ind'-1)+substr("`vlist'",`ind'+`length',.) }
         local i=`i'+1
      }

sort locus `vlist'
qui by locus `vlist' : gen double freq = sum(`pr')
qui _unique subject
qui gen double eprob=freq/(2*r(unique))
qui by locus `vlist' : keep if _n==_N

sort `vlist' locus

/****************************************************************
 * A routine to remove rare haplotypes but not zero haplotypes
 * and also remove the degrees of freedom
 ****************************************************************/

if `rare'~=0 {
  di "Removing rare haplotypes...."

/*
  gen rare= eprob<`rare'
  count if rare==1
  local nrare=r(N)

      local i 1
      local slist ""
      qui gen str40 plocus = locus
      while `i'<=$nloc {
         qui gen len = index(plocus,".")-1
         qui gen l`i'=real(substr(plocus,1,len))
         if `i'==$nloc { qui replace l`i'=real(plocus) }
         else { qui gen len2 = index(plocus,".")+1
         qui replace plocus=substr(plocus,len2,.) }
         drop len
         cap drop len2
   local slist "`slist' l`i'"
         local i=`i'+1
      }
     drop plocus
  gen Efreqold = cond(rare==1, 0 ,.)
  sort `slist'
  save constrain,replace
*/

  gen double rare= eprob<`rare' & eprob>0
  count if rare==1
  local nrare=r(N)

  drop if rare==1

  list locus `vlist' freq eprob if rare==1, noobs


}

/**********************************
 * Display the testing expressions
 **********************************/

local allnop = `regnop'+`nparms'

if "`quiet'"=="" {
di ""
di as text "Quantitative-`haptext' Estimation by EM algorithm"
di in smcl "{dup 49:{c -}}"
di as res " No. loci ", _col(20) "= $nloc"
di " Log-Likelihood ", _col(20) "= `llh'"
di " Tot. parameters ", _col(20) "=" , `allnop'
/* di " Log-Likelihood under null ", _col(20) "= `llh0'"
 * di " 2*LogLikelihoodRatio  ", _col(20) "=", 2*(`llh'-`llh0')
 * di " Df ", _col(20) "=" , `df'
 */
di " No. cells      (from log-linear)", _col(20) "=" , `ncells'
di " No. parameters (from log-linear)", _col(20) "=" , `nparms'
di " No. parameters (from regression)", _col(20) "=" , `regnop'
/* di " No of rare parameters dropped ", _col(20) "=", `nrare' */
di
}

/************************************************
 * Should display the expected frequencies and
 * the imputed frequencies.
 ************************************************/

if "`display'"~="" {
   sort locus `vlist'
   di in gr "Imputed Frequencies"
   qui gen str80 `haptvar'=locus
   qui compress `haptvar'
   list `haptvar' `vlist' freq eprob, noobs
   qui drop `haptvar'
   di in gr "Expected Frequencies"
}

 qui use "`imputef'",clear
 sort locus `vlist'
 rename Efreq freq
 tempvar total
 gen double `total'=sum(freq)
 gen double eprob=freq/`total'[_N]
 sort locus `vlist'

if "`display'"~="" {
   qui gen str80 `haptvar'=locus
   qui compress `haptvar'
   list `haptvar' `vlist' freq eprob, noobs
   qui drop `haptvar'
   * LOOK at the total frequency
   qui gen double totf = sum(freq)
   di
   di "TOTAL FREQ is ", totf[_N]
}

global loglik=`llh'

keep locus `vlist' freq eprob
if "`using'"~="" {

 /* Must create the l1 l2 l3...  variables from locus for the profile likelihood */

  local i 1
  qui gen str40 plocus = locus
  while `i'<=$nloc {
      qui gen len = index(plocus,".")-1
      qui gen l`i'=real(substr(plocus,1,len))
      if `i'==$nloc { qui replace l`i'=real(plocus) }
      else { qui gen len2 = index(plocus,".")+1
      qui replace plocus=substr(plocus,len2,.) }
      drop len
      cap drop len2
      local i=`i'+1
  }
  drop plocus

  cap save "`using'", replace
}


if "`display'"~="" {
  use "`yhats'",replace
  qui compress
  list locus1 locus2 mean, noobs
}

/****************************************************************
 * Saving the model ipf string and the loglikelihood and
 * degrees of freedom
 ****************************************************************/

global hapmod`model'="L=`ipf' R=`regress' "
global hapdf`model'="`df'"
global hapnp`model'="`allnop'"
global hapllhd`model'="`llh'"

if "`lrtest'"~="" {
   tokenize "`lrtest'"
   local m1 "hapmod`1'"
   local m2 "hapmod`2'"
   local l1 "hapllhd`1'"
   local l2 "hapllhd`2'"
   local d1 "hapdf`1'"
   local d2 "hapdf`2'"
   local n1 "hapnp`1'"
   local n2 "hapnp`2'"

   /******************************************
    * Check whether these MACROS exist or not
    ******************************************/

   local error 0
   if "$`l2'" == "" {
      di in red "GLOBAL: `l2' does not exist is there a model `2'?"
      local error 1
   }
   if "$`l1'" == "" {
      di in red "GLOBAL: `l1' does not exist is there a model `1'?"
      local error 1
    }
   if "$`m2'" == "" {
      di in red "GLOBAL: `m2' does not exist is there a model `2'?"
      local error 1
    }
   if "$`m1'" == "" {
      di in red "GLOBAL: `m1' does not exist is there a model `1'?"
      local error 1
   }
   if "$`d2'" == "" {
      di in red "GLOBAL: `d2' does not exist is there a model `2'?"
      local error 1
   }
   if "$`d1'" == "" {
      di in red "GLOBAL: `d1' does not exist is there a model `1'?"
      local error 1
   }
   if "$`n2'" == "" {
      di in red "GLOBAL: `n2' does not exist is there a model `2'?"
      local error 1
   }
   if "$`n1'" == "" {
      di in red "GLOBAL: `n1' does not exist is there a model `1'?"
      local error 1
   }
   if `error'~=1 {
     di
     di as text in smcl "{dup 37:{c -}}"
     di "Likelihood Ratio Test Comparing Model "
     di "$`m2' to "
     di "$`m1'"
     di as text in smcl "{dup 37:{c -}}"
     di as res " llhd1 (np1)           =", $`l1', $`n1'
     di " llhd2 (np2)           =", $`l2', $`n2'
     di
     di "-2*(llhd2-llhd1)  =",-2*($`l2'-$`l1')
     di "Change in np      = ", $`n1'-$`n2'
     local lrt = -2*($`l2'-$`l1')
     local chnp = $`n1'-$`n2'
     local pv=chiprob(`chnp',`lrt')
     di "p-value           = ", chiprob(`chnp',`lrt')
     if `chnp'<0 {
       di as error "WARNING: negative chi-squared statistic"
       di as error "       The order of models in lrtest() is wrong"
     }
     else {
       if `pv'<0.05 { di as text "Accept Model $`m1' at 5% significance level" }
       else {  di as text "Accept Model $`m2' at 5% significance level" }
     }
     return scalar lrtpv = `pv'
     return scalar lrtnp = `chnp'
     return scalar lrtchi = `lrt'
   }
}

qui !rm dummy.dta
use "`origin'",clear

if "`problemllhd'"=="1" { save problemllhd,replace  }

end

/*********************************************************
 * Tabulate for both locus the expected frequency
 * The 3rd and fourth variables contain the counting
 * vectors
 *********************************************************/

program define tabduo
version 7.0
syntax	varlist(min=2 max=100), [BY(string)]
tokenize `varlist'

if "`by'"=="" {
	stack `1' `3' `2' `4', into(temp one) clear
	sort temp
	qui by temp: gen long freq=sum(one)
	qui by temp: keep if _n==_N
}
if "`by'"~="" {
	stack `1' `3' `by' `2' `4' `by', into(temp one `by') clear
	sort temp `by'
	qui by temp `by': gen long freq=sum(one)
	qui by temp `by': keep if _n==_N
}
end

/*********************************************************
 * Take the 2 haplotypes from each subject
 * and do some basic tabulating saving the resulting
 * tabulate in merge and merge2, these two represent
 * the different sorted variables
 **********************************************************/

program define tabhap
version 7.0
syntax varlist(min=2 max=100)
tokenize `varlist'

cap confirm new file merge.dta
if _rc~=0 { di in red "merge.dta will be deleted within the program" }
cap confirm new file merge2.dta
if _rc~=0 { di in red "merge2.dta will be deleted within the program" }

stack `1' `2', into(haplo) clear
qui egen hapgrp = group(haplo)
sort haplo
qui by haplo: keep if _n==_N
keep haplo hapgrp
cap save merge,replace
sort hapgrp
cap save merge2,replace
end

/*************************************************************************
 * Calculate all the 2*($nloc-1) possible haplotypes
 * given the
 * observed data for each phase and person.
 * have locus1 and locus2 contain the string versions of the haplotypes
 * and the global unknown having the number of subjects with phase unknown
 **************************************************************************
 * 8/11/99 - The strings are out and separate variables are in
 **************************************************************************/

program define haplotyp
version 7.0
syntax [varlist] [,NOISE KNOWN PHASE(string) MV]
tokenize `varlist'


cap confirm new variable locus1 locus2 subject
if _rc~=0 {
  di in red "You must rename the following variable"
  confirm new variable locus1 locus2 subject
}
tempvar subj expand

/* Note that subj contains the subject id numbers and is renamed subject */

qui gen long subject = _n
qui gen long `subj' = _n

if "`mv'"~="" {
  di as text "EXPANDING MISSING DATA....."

  local li 1
  while `li'<=$nloc {
    local wc1=2*`li'-1
    local wc2=`wc1'+1
    local root1: word `wc1' of $all_name
    local root2: word `wc2' of $all_name

    qui count if `root1'==.
    local c1 = `r(N)'
    qui count if `root2'==.
    local cnt = `c1'+`r(N)'

    if `cnt'>0 {
      di as res "There are `cnt' missing values at locus `li'"
      qui tab `root1' , matrow(row)
      qui tab `root2' , matrow(col)

      /* NEED to make one matrix with all the values at locus i called unique */

      mat values = row \ col
      local j 1
      while `j'<=rowsof(values) {
        if `j'==1 {
          mat unique = values[1,1]
          local j =`j'+1
        }
        local not 0
        local jj 1
        while `jj'<`j' {
          if values[`j',1]==values[`jj',1] {
            local not 1
            local jj=`j'
          }
          local jj=`jj'+1
        }
        if `not'==0 { mat unique = unique \ values[`j',1] }

       local j = `j'+1
      }

    /* The matrix unique now contains just one copy of the alleles */

      /* Replace missing with one from each of unique
       * FOR TWO loci this would be the number of unique*(unique+1)/2
       */

      tempvar temp
      sort subject
      gen long `temp'=_n
      local missex = rowsof(unique)
      local missex = `missex'*(`missex'+1)/2
      qui expand  `missex' if `root1'==. | `root2'==.
      sort `temp'

      /* Create the new phenotypes */

      local lineno 1
      local i 1
      while `i'<=rowsof(unique) {
         local j = `i'
         while `j'<=rowsof(unique) {

           qui by `temp': replace `root1' = cond(`root1'==. & _n==`lineno', unique[`i',1],`root1')
           qui by `temp': replace `root2' = cond(`root2'==. & _n==`lineno', unique[`j',1],`root2')
           local lineno = `lineno'+1

         local j = `j'+1
         }
      local i =`i'+1
      }


    } /* end of if dealing with missing */

    local li =`li'+1  /*loop of loci */
  }

}
  di

if "`known'"~="" & "`phase'"=="" {
	qui gen str40 locus1=""
	qui gen str40 locus2=""
	/*******************************************
	 * Construct locus strings from alleles
	 *******************************************/
	sort subject
	global unknown = 0
	local i 1
	while `i'<=$nloc {
		local wc1=2*`i'-1
		local wc2=`wc1'+1
		local root1: word `wc1' of $all_name
		local root2: word `wc2' of $all_name

		if `i'==1 {
			qui replace locus1 =string(`root1')
			qui replace locus2 =string(`root2')
		}
		else {
			qui replace locus1 = locus1+"."+string(`root1')
			qui replace locus2 = locus2+"."+string(`root2')
		}


	local i=`i'+1
	}
}
if "`known'"=="" & "`phase'"=="" {

	local root1: word 1 of $all_name
	local root2: word 2 of $all_name
	qui gen str40 locus1=string(`root1')
	qui gen str40 locus2=string(`root2')
	qui gen `expand'=.

	/*******************************************
 	 * Construct locus strings from alleles and
	 * also expand to all possibilities
	 *******************************************/

        if "`mv'"~="" { local i 1}
        if "`mv'"=="" { local i 2}

	while `i'<=$nloc {
		sort `subj'
		local wc1=2*`i'-1
		local wc2=`wc1'+1
		local root1: word `wc1' of $all_name
		local root2: word `wc2' of $all_name

                qui replace `expand'= 2*(`root1'~=`root2')

		qui replace subject=_n
		qui expand `expand'
		sort subject

		if `i'>1 {
                  qui by subject: replace locus1= locus1+"."+string(cond(_n==2,`root2',`root1'))
		  qui by subject: replace locus2= locus2+"."+string(cond(_n==2,`root1',`root2'))
                }
                if `i'==1 {
                  qui by subject: replace locus1= string(cond(_n==2,`root2',`root1'))
		  qui by subject: replace locus2= string(cond(_n==2,`root1',`root2'))
                }

	local i=`i'+1
	}
	qui drop subject `expand'
	qui rename `subj' subject
}

if "`phase'"~="" {
	local root1: word 1 of $all_name
	local root2: word 2 of $all_name
	qui gen str40 locus1=string(`root1')
	qui gen str40 locus2=string(`root2')
	qui gen `expand'=.
	cap confirm variable `phase'
	if _rc~=0 {
		di in red "variable `phase' does not exist!"
		exit 111
	}

	/*******************************************
	 * Construct locus strings from alleles and
	 * also expand to all possibilities
	 *******************************************/

        if "`mv'"~="" { local i 1}
        if "`mv'"=="" { local i 2}

	while `i'<=$nloc {
		sort `subj'
		local wc1=2*`i'-1
		local wc2=`wc1'+1
		local root1: word `wc1' of $all_name
		local root2: word `wc2' of $all_name


	        qui replace `expand'= cond(`phase'==0,2*(`root1'~=`root2'),1)

		qui replace subject=_n
		qui expand `expand'
		sort subject

                if `i'>1 {
                  qui by subject: replace locus1= locus1+"."+string(cond(_n==2,`root2',`root1'))
		  qui by subject: replace locus2= locus2+"."+string(cond(_n==2,`root1',`root2'))
                }
                if `i'==1 {
                  qui by subject: replace locus1= string(cond(_n==2,`root2',`root1'))
		  qui by subject: replace locus2= string(cond(_n==2,`root1',`root2'))
                }

	local i=`i'+1
	}
	qui drop subject `expand'
	qui rename `subj' subject

}
qui compress

end

/****************************************************************
 * My program to stack variables
 * Go thro' varlist  if `1'~=`2' then rename `2'
 * `1' and then drop `1' at the end append in the original file
 ****************************************************************/

program define _stack
version 7.0
syntax varlist(min=1) [using/] [if],[NOISE START KNOWN PHASE(string) BY(string) ACC(real 0.001) DEBUG]
tokenize `varlist'

gen _stack=1
tempfile stack
qui save "`stack'"

local i 1
while "``i''"~="" {
	local p=`i'
	local i = `i'+1
	if "``p''"~="``i''" {
		drop ``p''
		rename ``i'' ``p''
	}
	local i=`i'+1
}

qui replace _stack=2

append using `stack'

end

/**********************************************
 * BETTER explanation needed....
 * MY unstack
 * First the variables and the values are given to the function e.g. locus and "1 2"
 **********************************************/

program define _ustack
version 7.0
syntax varlist(min=1) [using/] [if], BY(string) VALues(string) [NOISE START KNOWN PHASE(string) ]
tokenize `varlist'

tokenize "`values'", parse(" ")
tempfile first merge

qui by `by': gen long merg=_n
save "`first'"

keep if `by'==`1'
tokenize "`varlist'"
keep `varlist' merg
while "`1'"~="" {
	rename `1' `1'1
mac shift 1
}
sort merg
save "`merge'"

use "`first'"
tokenize `values', parse(" ")
keep if `by'==`2'
tokenize `varlist'
while "`1'"~="" {
	rename `1' `1'2
mac shift 1
}

sort merg
merge merg using `merge'

end

/*******************************************
 * This programs unique function
 *******************************************/

program define _unique, rclass
   version 7.0
   syntax varlist(min=1 max=1)
   tokenize "`varlist'"
   local var `1'

preserve
sort `var'
qui by `var': keep if _n==1
return scalar N=_N
global S_1 =_N
qui drop if `var'==.
global S_2 =_N
return scalar unique=_N

restore

end

/***********************************************************************
 * This function creates the dummy variables.
 * Note that a haplotype of interest is required! because this model
 * assumes that you have binary markers
 *
 ************************************************************************/

program define _mkdummy, rclass
version 7.0
syntax [varlist]  [, HAPint(string) Reg(string) Dom(string)]

/********************************************
 * Find out the reference haplotype
 ********************************************/

sort locus1 locus2
if "`hapint'"=="none" {
  di as text "Creating dummy variables"
  di in smcl as text "{dup 24:{c -}}"
  di as error  _continue "The reference haplotype is NOT specified "
  local hapint = locus1[_N]
  di as res ": It will be `hapint'"
}
else {
  di as text "Creating dummy variables"
  di in smcl as text "{dup 24:{c -}}"
  di as res "The reference haplotype is `hapint' "
}

/*******************************************************
 * create l1a l1b l2a l2b .....
 * lia is the allele at locus 1 for marker i
 * lib is the allele at locus 2 for marker i
 *******************************************************/

   tempvar plocus1 plocus2
   local i 1
   local vlist " "
   qui gen str40 `plocus1' = locus1
   qui gen str40 `plocus2' = locus2
   while `i'<=$nloc {
      tempvar len len2
      qui gen `len' = index(`plocus1',".")-1
      qui gen l`i'a=real(substr(`plocus1',1,`len'))
      if `i'==$nloc { qui replace l`i'a=real(`plocus1') }
      else { qui gen `len2' = index(`plocus1',".")+1
      qui replace `plocus1'=substr(`plocus1',`len2',.) }
      drop `len'
      cap drop `len2'
      qui gen `len' = index(`plocus2',".")-1
      qui gen l`i'b=real(substr(`plocus2',1,`len'))
      if `i'==$nloc { qui replace l`i'b=real(`plocus2') }
      else { qui gen `len2' = index(`plocus2',".")+1
      qui replace `plocus2'=substr(`plocus2',`len2',.) }
      drop `len'
      cap drop `len2'

      local vlist "`vlist' l`i'b"
      local i=`i'+1
   }

   drop `plocus1' `plocus2'

/*********************************************************
 * Split up the hapint string into alleles at
 * each location
 * macros l1 l2 l3 ... contain the allele of interest at
 * that locus
 *********************************************************/

  local i 1
  while `i'<=$nloc {
      local len = index("`hapint'",".")-1

      if `len'==-1 & `i'~=$nloc {
        di in red "HAPINT TOO short are you missing a locus??"
        exit(198)
      }

      local l`i'=real(substr("`hapint'",1,`len'))
      if `i'==$nloc {  local l`i'=real("`hapint'") }
      else { local  len2 = index("`hapint'",".")+1
      local hapint=substr("`hapint'",`len2',.) }
      local i=`i'+1
   }
   if index("`hapint'",".")~=0 { di in red "HAPINT is too long!!" }

/***********************************************
 * Process the regression string
 * 1) Set up the dummy variable for constant
 * 2) then for the other possible models
 ***********************************************/

if "`reg'"=="1" {
  local reg ""
}

/* Process the []*[]*[] parts... Haplotype effects could be additive or dominant */

local brac "1"
local list 1
while "`reg'"~="" {

  /* Go through terms checking what is between ][ and putting it in start and parsing within [] */

  gettoken brac reg:reg, parse("]")
  if index("`brac'","[")~=0 {
    local start = substr("`brac'",1,index("`brac'","[")-1)
    local brac = substr("`brac'",index("`brac'","[")+1,.)
  }

  /* create list1 list2 macros that store the within loci effects */

  if "`brac'"~="]" {
    tokenize "`brac'", parse ("+*")
    local list`list' ""
    if "`2'"=="+" {
      if "`1'"=="`3'" { local list`list' "`1'a&`3'b" }
      else { local list`list' "`1' `3'" }
    }
    else {
      if "`1'"=="`3'" { local list`list' "`1'a&`3'b `1'a~=`3'b" }
      else { local list`list' "`1' `3' `1'~=`3'" }
    }
  }

  if "`start'"=="*" {
    local temp ""
    foreach term of local list`list' {
      foreach term2 of local submod {
        local temp "`temp' `term'.`term2'"
      }
    }
  }
  local submod "`submod' `list`list'' `temp'"

  local list = `list'+1
}

/* Expand out the &'s */

local tesubmod ""
foreach term of local submod {
  local te ""
  /* Select those terms with two pluses  */

  if index("`term'","&")~=0 {
    gettoken first term:term, parse(".")

    local parms1 ""
    local parms2 ""
    local specialcase 0  /* for when the term starts with a dominance term */
    while "`first'"~="" {
      if "`first'"=="." { gettoken first term:term, parse(".") }

      gettoken one first:first, parse("&")
      gettoken two first:first, parse("&")
      gettoken two first:first, parse("&")

      if "`parms1'"=="" & "`two'"=="" {
        local specialcase 1
      }

        local te ""
        if "`parms1'"=="" {
          local parms1 "`one'"
        }
        else {
          foreach var of local parms1 {
            if "`two'"~="" & `specialcase'==0 { local te "`te' `var'.`one' `var'.`two'" }
            if "`two'"~="" & `specialcase'==1 { local te "`te' `var'.`one'" }
            if "`two'"=="" { local te "`te' `var'.`one'" }
          }
        }
        if "`te'"~="" { local parms1 "`te'" }

        local te ""
        if "`parms2'"=="" {
          if "`two'"~="" { local parms2 "`two'" }
          else { local parms2 "`one'" }
        }
        else {
          foreach var of local parms2 {
            if "`two'"~="" & `specialcase'==0 { local te "`te' `var'.`two' `var'.`one'" }
            if "`two'"~="" & `specialcase'==1 {
              local te "`te' `var'.`two'"
              local specialcase 0
            }
            if "`two'"=="" { local te "`te' `var'.`one'" }
          }
        }
        if "`te'"~="" { local parms2 "`te'" }

      gettoken first term:term, parse(".")

    }
    local te ""
    local t1 1
    foreach t of local parms1 {
      local t2 1
      foreach u of local parms2 {
        if `t1'==`t2' { local te "`te' `t'&`u'" }
        local t2 =`t2'+1
      }
      local t1=`t1'+1
    }
  }
  else { local  tesubmod "`tesubmod' `term'" }
  local tesubmod "`tesubmod' `te'"
}

local submod "`tesubmod'"

gen _d0 = 1
lab var _d0 "Constant"
local model "_d0"

local ndum 1
foreach term of local submod {
  gen _d`ndum' = 1
  lab var _d`ndum' "`term'"
  local model "`model' _d`ndum'"

 if "`term'"=="l2a.l1a&l2b.l1b" { local yep 1}
  else { local yep 0}

  gettoken left term:term, parse("&")
  gettoken temp term:term, parse("&")
  gettoken right term:term, parse("&")

  tempvar temp1 temp2
  gen `temp1'=1
  tokenize "`left'", parse(".")
  while "`1'"~="" {
    while "`1'"=="." { mac shift 1 }
    if index("`1'","~=")==0 {
      local thislocus = substr("`1'",index("`1'","l")+1,.)
      local len = length("`thislocus'")
      local thislocus = substr("`thislocus'",1,`len'-1)
      qui replace `temp1' = `temp1'*(`1'==`l`thislocus'')
    }
    else {  qui replace `temp1' = `temp1'*(`1') }
    mac shift 1
  }
  qui replace _d`ndum' = `temp1'
  if "`right'"~="" {
    gen `temp2'=1
    tokenize "`right'", parse(".")
    while "`1'"~="" {
      while "`1'"=="." { mac shift 1 }
        if index("`1'","~=")==0 {
           local thislocus = substr("`1'",index("`1'","l")+1,.)
           local len = length("`thislocus'")
           local thislocus = substr("`thislocus'",1,`len'-1)
           qui replace `temp2' = `temp2'*(`1'==`l`thislocus'')
        }
        else { qui replace `temp2' = `temp2'*(`1') }
      mac shift 1
    }
    qui replace _d`ndum' = _d`ndum'+`temp2'
  }


  local ndum = `ndum'+1
}



/* COULD drop subject at the moment
 * _tidy
 */

sort locus1 locus2 subject
keep locus1 locus2 subject _d*
qui compress
qui save dummy,replace

return local model  "`model'"
return local modela  "`modela'"
return local modelb  "`modelb'"
return local nvars = `ndum'-1
end

/********************************
 * Take the number in `1'
 * get binary numbers
 ********************************/

program define _bin, rclass
version 7.0
local num `1'
local i = `2'-1
while `i'>=1 {
  local fact = 2^`i'
  if  mod(`num',`fact')~= `num' {
    local ii = `i'+1
    local locs "`locs' `ii'"
    return scalar t`ii' = `ii'
    local num = `num' - `fact'
  }
  local i = `i'-1
}
if `num'==1 {   return scalar t1 = 1 }
if `num'==1 { local locs "`locs' 1" }
return local locs "`locs'"

end

/********************************
 * Take the number in `1'
 * get binary numbers
 ********************************/

program define _bin2, rclass
version 7.0
local num `1'
local i = `2'-1
while `i'>=1 {
  local fact = 2^`i'
  if  mod(`num',`fact')~= `num' {
    local ii = `i'+1
    local locs "`locs' 1"
    local num = `num' - `fact'
  }
  else { local locs "`locs' 0" }
  local i = `i'-1
}
if `num'==1 { local locs "`locs' 1" }
else { local locs "`locs' 0" }
return local locs "`locs'"

end

/*************************
 * drop _d*a
 *************************/

program define _tidy
version 7.0
syntax [varlist]

tokenize "`varlist'"
while "`1'"~="" {
  if substr("`1'",1,2)=="_d" & substr("`1'",-1,1)=="a" {
   drop `1'
  }
  if substr("`1'",1,2)=="_d" & substr("`1'",-1,1)=="b" {
   drop `1'
  }
  mac shift 1
}

end

/*****************************************************
 *
 *
 *****************************************************/

prog def _mkdum2, rclass
version 7.0
syntax [varlist]  [, ADD(string)]

keep locus1 locus2 subject
/*******************************************************
 * create l1a l1b l2a l2b .....
 * lia is the allele at locus 1 for marker i
 * lib is the allele at locus 2 for marker i
 *******************************************************/

 tempvar plocus1 plocus2
 local i 1
 local vlist1 ""     /* VLIST1 and VLIST2 and INLIST used later  */
 local vlist2 ""
 local inlist ""

 qui gen str40 `plocus1' = locus1
 qui gen str40 `plocus2' = locus2
 while `i'<=$nloc {
   tempvar len len2
   qui gen `len' = index(`plocus1',".")-1
   qui gen l`i'a=real(substr(`plocus1',1,`len'))
   if `i'==$nloc { qui replace l`i'a=real(`plocus1') }
   else { qui gen `len2' = index(`plocus1',".")+1
   qui replace `plocus1'=substr(`plocus1',`len2',.) }
   drop `len'
   cap drop `len2'
   qui gen `len' = index(`plocus2',".")-1
   qui gen l`i'b=real(substr(`plocus2',1,`len'))
   if `i'==$nloc { qui replace l`i'b=real(`plocus2') }
   else { qui gen `len2' = index(`plocus2',".")+1
   qui replace `plocus2'=substr(`plocus2',`len2',.) }
   drop `len'
   cap drop `len2'

   local vlist1 "`vlist1' l`i'a"
   local vlist2 "`vlist2' l`i'b"
   local inlist "`inlist' l`i'"

   local i=`i'+1
 }
 drop `plocus1' `plocus2'

/********************************************************
 * Get a matrix that contains the alleles for each locus
 ********************************************************/

 preserve
 stack `vlist1' `vlist2', into(`inlist') clear
 local i 1
 while `i'<=$nloc {
   qui tab l`i', matrow(tem`i')
   if rowsof(tem`i')>1 { mat m`i' = tem`i'[2...,1...] }
   else { mat m`i' = tem`i' }
   local i = `i'+1
 }
 restore

/********************************************************
 * Create additive variables per locus
 ********************************************************/

 local i 1
 while `i'<=$nloc {
   local j 1
   while `j'<= rowsof(m`i') {
     local allele = m`i'[`j',1]
     qui gen _dd`i'a`allele'= (l`i'a==`allele')+(l`i'b==`allele')
     lab var _dd`i'a`allele' "l`i'(`allele')"

     local j =`j'+1
   }
   local i =`i'+1
 }

/*********************************************************
 * Figure out what additive terms are included
 *********************************************************/

gen _d0 = 1
local  model "_d0"
label variable _d0 "1"

if "`add'"=="1" {
  local add ""
}

local di 1
while "`add'"~="" {
  gettoken marg add: add, parse("+")  /* For each marginal model */
  while "`marg'"=="+" {
    gettoken marg add: add, parse("+")
  }
  mat mmod = (0)
  tokenize "`marg'", parse("*")
  local terms 0
  while "`1'"~="" {
    local terms = `terms'+1
    mat thisloc = real(substr("`1'",2,1) )
    mat mmod = mmod \ thisloc
    mac shift 2
  }
  mat mmod = mmod[2...,1]

/* This bit does the combinations using matrices as the dataset could not be
   expanded being too big */

  local i 1
  while `i'<2^`terms' {
      _bin `i' `terms'

      cap mat drop comb
      local wi 1
      local wloc: word `wi' of `r(locs)'
      while "`wloc'"~="" {
        local thisloc= mmod[`wloc',1]
        cap qui mat list comb
        if _rc~=0 { mat comb = m`thisloc' }
        else {
          mat newcomb = comb
          local cdim = rowsof(comb)
          local ai 1
          while `ai'<=rowsof(m`thisloc') {
            local all = m`thisloc'[`ai',1]
            mat temp = J(`cdim',1,`all')
            if `ai'==1 { mat comb=newcomb,temp }
            else { mat comb = comb \ (newcomb , temp) }
            local ai=`ai'+1
            mat drop temp
          }
          mat drop newcomb
        }
        local wi=`wi'+1
        local wloc: word `wi' of `r(locs)'
      }

/* now matrix comb has the combinations */

      local j 1
      while `j'<= rowsof(comb) {
        gen _d`di'=1
        local k 1
        while `k'<=colsof(comb) {
          local wloc: word `k' of `r(locs)'
          local thisloc = mmod[`wloc',1]
          local all = comb[`j',`k']
          qui replace _d`di'=_d`di'*_dd`thisloc'a`all'
          local lab: variable label _dd`thisloc'a`all'
          local lab2: variable label _d`di'
          if "`lab2'"=="" { label variable _d`di' "`lab'"}
          else { label variable _d`di' "`lab2'*`lab'"  }
          local k =`k'+1
        }
      local model "`model' _d`di'"
      local di = `di'+1
      local j=`j'+1
      }

      local i =`i'+1
  }


} /* END of while add loop */


qui drop _dd*
sort locus1 locus2 subject
keep locus1 locus2 subject _d*
qui compress
qui save dummy,replace

return local model  "_d*"
return local nvars = `di'-1
end

/******************************************
 * BUILDING the menu system for easy use
 ******************************************/

prog def _qmenu
version 7.0
syntax [varlist]

win c clear
local statnloc 10

/* Window width and height textheight */

local winw 240
local winh 280
local texth 7
local leftmargin 5
local rightmargin =`winw'-5

/* Initialising globals */

local i 1
while `i'<= `statnloc' {
  global statloc`i' ""
  local i = `i'+1
}
global Qadd ""
global Qipf ""
global Qvar ""
global Qtvar ""
global infoqt ""
global infoqt1 ""
global Qcommand ""

/*Varlist options */

global Qsel "Select variables for:"
global Qmany "Loci"
global Qqt "Quantitative Trait"
global Qvarlist "`varlist'"
window control static Qsel 5 10 110 `texth' center
window control static Qqt 60 20 50 `texth' center
window control ssimple Qvarlist 60 30 50 100 Qtvar
window control static Qmany 5 20 50 10 center
window control msimple Qvarlist 5 30 50 100 Qvar

/* BUTTONS */

local tey = `winh'-11-15
global Qvchk1 "qhapupdate 0"
global Qvchk2 "qhapupdate 1"
window control button "Apply" 5 `tey' 30 11 Qvchk1
window control button "Add to Review" 40 `tey' 55 11 Qvchk2

/* Get rid of window */

global Qrun "exit 3000"
global Qexit "exit 3001"
window control button "Run command" 100 `tey' 55 11 Qrun
window control button "Exit" 160 `tey' 30 11 Qexit


/* INFORMATION
 * Display info qdix and qdiy control the top left corner */

local qdix=`winw'-95
local qdiy 30
local qdisx = `qdix'+35
local qdiw = `winw'-5-`qdix'

global Qdi "Information"
window control static Qdi `qdix' 30 `qdiw' 100 blackframe
window control static Qdi `qdisx' 27 30 7 center

/* Put in pairs of vars */
tokenize $Qvar
local i 1
while `i' <= `statnloc' {
  local tey = `qdiy'+10
  local tex = `qdix'+10
  local tew = `qdiw'-20
  local staty = `tey' + 7*(`i'-1)
  win c static statloc`i' `tex' `staty' `tew' `texth' left
  local i = `i'+1
}
local tey=`staty'+10
win c static infoqt1 `tex' `tey' `tew' `texth'
local tey=`tey'+`texth'
win c static infoqt `tex' `tey' `tew' `texth'

/* Display the saturated model for the haplotypes */

global Qllm "Haplotype Model"
local tey=`winh'-11-15-85
local teyy = `tey'-3
local tey2 = `tey'+9
local tew = `rightmargin'-`leftmargin'
local tew2= `tew'-20
local tex = `leftmargin'+10
local temid = int((`rightmargin'-`leftmargin')/2)-30
window control static Qllm `leftmargin' `tey' `tew' 20 blackframe
window control static Qllm `temid' `teyy' 60 7 center
window control static Qipf `tex' `tey2' `tew2' `texth' center

/* Display a check box to say whether you want to specify an haplotype */

global Qhi_rad 1
global Qhapint "<specify haplotype>"
local tex= `leftmargin'+1
local tey= `winh'-11-15-107
local tew  70
win c radbegin "Haplotype of interest" `tex' `tey' `tew' `texth' Qhi_rad
local tey2 = int(`tey'+`texth'/2)
local tex2 = `tex'+`tew'+1
local texth2 = `texth'+3
win c edit `tex2' `tey2' 60 `texth2' Qhapint
local tey = `tey'+10
*win c radend "All haplotypes" `tex' `tey' `tew' `texth' Qhi_rad

/* Display three models with check box and ipf() syntax box */

global Qqm "Common Quantitative Models"
global Qrad 1
global Qmod1 ""
global Qmod2 ""
global Qmod3 ""
global Qmod4 ""
global Qmod5 ""

local tey=`winh'-11-15-60
local teyy = `tey'-3
local tew = `rightmargin'-`leftmargin'
local temid = int((`rightmargin'-`leftmargin')/2)-30
local tew2= `tew'-20
local tex = `leftmargin'+5
local tey2 = `tey'+9
window control static Qqm `leftmargin' `tey' `tew' 55 blackframe
window control static Qqm `temid' `teyy' 84 `texth' center
local tey3 = `tey'+7
local tex2 = `tex'+80
win c radbegin "Constant Model" `tex' `tey3' 75 `texth' Qrad
win c static Qmod1  `tex2' `tey3' 90 `texth'
local tey3 = `tey3'+9
win c radio "SAM" `tex' `tey3' 90 8 Qrad
win c static Qmod2  `tex2' `tey3' 90 `texth'
local tey3 = `tey3'+9
win c radio "MAM" `tex' `tey3' 90 `texth' Qrad
win c static Qmod3  `tex2' `tey3' 90 `texth'
local tey3 = `tey3'+9
win c radio "No parental imprinting"  `tex' `tey3' 90 `texth' Qrad
win c static Qmod4  `tex2' `tey3' 90 `texth'
local tey3 = `tey3'+9
win c radend "Saturated"  `tex' `tey3' 90 `texth' Qrad
win c static Qmod5  `tex2' `tey3' 90 `texth'

/* Display the syntax */

global Qdis ""
local tey=`winh'-1-`texth'
local tex=`leftmargin'+31
window control static Qdis `leftmargin' `tey' 30 `texth' left
window control static Qcommand `tex' `tey' 200 `texth' left

/* ENd of windowing */

window dialog "A window to help with the syntax" . . `winw' `winh'

end