*! version 3.1 : October 25th, 2011
*! Jean-Benoit Hardouin, Myriam Blanchin
************************************************************************************************************
* raschpower: Estimation of the power of the Wald test in order to compare the means of the latent trait in two groups of individuals
*
* Version 1 : January 25, 2010 (Jean-Benoit Hardouin)
* Version 1.1 : January 26, 2010 (Jean-Benoit Hardouin)
* Version 1.2 : November 1st, 2010 (Jean-Benoit Hardouin)
* version 1.3 : May 2th, 2011 (Jean-Benoit Hardouin)
* version 1.4 : July 7th, 2011 (Jean-Benoit Hardouin) : minor corrections
* version 1.5 : July 11th, 2011 (Jean-Benoit Hardouin) : minor corrections
* version 2 : August 30th, 2011 (Jean-Benoit Hardouin, Myriam Blanchin) : corrections
* version 3 : October 18th, 2011 (Jean-Benoit Hardouin, Myriam Blanchin) : Extension to the PCM, -method- option, -nbpatterns- options, changes in the presentation of the results
* version 3.1 : October 25th, 2011 (Jean-Benoit Hardouin, Myriam Blanchin) : POPULATION+GH method
*
* Jean-benoit Hardouin, jean-benoit.hardouin@univ-nantes.fr
* Myriam Blanchin, myriam.blanchin@univ-nantes.fr
* EA 4275 "Biostatistics, Pharmacoepidemiology and Subjectives Measures in Health"
* Faculty of Pharmaceutical Sciences - University of Nantes - France
*
* News about this program : http://www.anaqol.org
* FreeIRT Project : http://www.freeirt.org
*
* Copyright 2010-2011 Jean-Benoit Hardouin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
************************************************************************************************************/

program define raschpowerpcm,rclass
syntax [varlist] [, n0(int 100) n1(int 100) Gamma(real .5) Difficulties(string) Var(real 1) Method(string) NBPatterns(int 2) nodata gammafix EXPectedpower(real -1)]
version 11

tempfile raschpowerfile
capture qui save "`raschpowerfile'",replace
tempname db d
if "`difficulties'"=="" {
   *matrix `d'=[-1\-.5\0\.5\1]
   matrix `d'=[-1.151, -0.987\-0.615, -0.325\-0.184, -0.043\0.246, 0.554\0.782, 1.724]
   *matrix `d'=[ -1.527, -1.019\-1.100, -0.793\-0.796, -0.369\-0.540, 0.152\-0.306, -0.220\-0.077, 0.147\0.156, 0.431\0.412, 0.685\0.716, 1.332\1.043, 1.572]
}
else {
   matrix `d'=`difficulties'
}
local nbitems=rowsof(`d')
local nbmodat=colsof(`d')+1
if "`method'"=="MEAN+GH"&`nbpatterns'*(`n1'+`n0')>=`=`nbmodat'^`nbitems'*2' {
   di in gr "The MEAN+GH will be inefficient compared to GH since the maximal number of pattern's responses"
   di in gr "is lesser than the number of pattern retained by the MEAN+GH method."
   di in gr "The -method- option is replaced by GH."
   local method GH
}
else if "`method'"=="" {
    if `nbmodat'^`nbitems'*2<1000 {
        local method GH
    }
    else if `nbmodat'^`nbitems'<10000 {
        local method MEAN+GH
    }
    else if `nbmodat'^`nbitems'<1000000 {
        local method MEAN
    }
    else  {
        local method POPULATION+GH
    }
}



di in gr "Method:  " in ye "`method'"
di in gr "Number of individuals in the first group:  " in ye `n0'
di in gr "Number of individuals in the second group: " in ye `n1'
di in green "Group effect: " in ye `gamma'
di in  gr "Variance of the latent trait: " in ye `var'
di in gr "Number of items: " in ye `nbitems'
di in green "Difficulties parameters of the items: "
tempname dd
matrix `dd'=`d''
local items
forvalues i=1/`nbitems' {
   local items "`items' item`i'"
}
local modalities
forvalues i=1/`=`nbmodat'-1' {
   local modalities "`modalities' delta_`i'"
}

matrix colnames `dd'=`items'
matrix rownames `dd'=`modalities'
matrix list `dd',noblank nohalf  noheader
di in gr "Number of studied response's patterns: " in ye `=`nbmodat'^`nbitems'*2'

matrix `dd'=`d'
local gamma=`gamma'

local tmp=1
qui matrix `db'=J(`=`nbitems'*(`nbmodat'-1)',1,.)
forvalues j=1/`nbitems' {
   forvalues m=1/`=`nbmodat'-1' {
      qui matrix `db'[`tmp',1]=`d'[`j',`m']
      local ++tmp
   }
}

if "`data'"=="" {
   clear
   if "`method'"!="POPULATION+GH"&"`method'"!="POPULATION+MEAN" {
      local temp=`nbmodat'^(`nbitems')
      qui range x 0 `=`temp'-1' `temp'
      qui g t=x
      loc i=`nbitems'
      qui count if t>0
      loc z=r(N)
      qui while `z'>0 {
         qui gen item`=`nbitems'-`i'+1'=floor(t/`nbmodat'^`=`i'-1')
         qui replace t=mod(t,`nbmodat'^`=`i'-1')
         qui count if t>0
         loc z=r(N)
         loc i=`i'-1
      }
      drop t
      qui expand 2
      qui gen group=0 in 1/`temp'
      qui replace group=1 in `=`temp'+1'/`=2*`temp''
   }
   else {
      qui simirt, clear pcm(`difficulties') cov(`var') group(`=`n1'/(`n1'+`n0')') deltagroup(`gamma') nbobs(1000000)
      qui drop lt1
      qui contract item* group, freq(freq)
      qui gen keep=0
      qui gsort +group -freq
      qui replace keep=1 in 1/`=`nbpatterns'*`n1''
      qui gsort -group -freq
      qui replace keep=1 in 1/`=`nbpatterns'*`n0''
      qui keep if keep==1
      qui count
      local tmp=r(N)
      di "Number of kept patterns:`tmp'"
      local method GH
   }
   qui gen mean=-`n1'*`gamma'/(`n0'+`n1') if group==0
   qui replace mean=`n0'*`gamma'/(`n0'+`n1') if group==1

   if "`method'"=="GH" {
      local temp=`nbmodat'^(`nbitems')
      local diff0=0
      qui gen proba=.
      local dixj=10
      qui count
      local tmp=r(N)
      forvalues i=1/`tmp' {
         local dix=floor(`tmp'/10)
         if mod(`i',`dix')==0 {
            if "`dixj'"!="10" {
               di ".." _c
            }
            di "`dixj'%" _c
            local dixj=`dixj'+10
         }
         local int=1
         forvalues j=1/`nbitems' {
            qui su item`j' in `i'
            local rep=r(mean)
            local diff0=0
            local diff1=`d'[`j',1]
            local sum "1+exp(x-`diff1')"
            forvalues m=2/`=`nbmodat'-1' {
               local diff`m'=`diff`=`m'-1''+`d'[`j',`m']
               local sum "`sum'+exp(`m'*x-`diff`m'')"
            }
            local int "(`int'*exp(`rep'*x-`diff`rep''))/(`sum')"
         }
         qui su mean in `i'
         local mean=r(mean)
         qui gausshermite `int',mu(`mean') sigma(`=sqrt(`var')') display
         qui replace proba=r(int) in `i'
      }
      di
   }
   else {
      qui gen proba=1
      forvalues i=1/`nbitems' {
         local diff0=0
         local diff1=`d'[`i',1]
         qui gen eps0=1
         qui gen eps1=exp(mean-`diff1')
         qui gen d=eps0+eps1
         forvalues m=2/`=`nbmodat'-1' {
            local diff`m'=`diff`=`m'-1''+`d'[`i',`m']
            qui gen eps`m'=exp(`m'*mean-`diff`m'')
            qui replace d=d+eps`m'
         }
         local listeps
         forvalues m=0/`=`nbmodat'-1' {
            qui replace proba=proba*eps`m'/d if item`i'==`m'
            local listeps `listeps' eps`m'
         }
         qui drop `listeps' d
      }
      if "`method'"=="MEAN+GH" {
      set tracedepth 1
         qui gen keep=0
         qui gsort -group -proba
         local min=min(`=`nbmodat'^`nbitems'',`=`n1'*`nbpatterns'')
         qui replace keep=1 in 1/`min'
         qui gsort +group -proba
         local min=min(`=`nbmodat'^`nbitems'',`=`n0'*`nbpatterns'')
         qui replace keep=1 in 1/`min'
         qui keep if keep==1
         qui su proba if group==0
         local sumproba0=r(sum)*100
         qui su proba if group==1
         local sumproba1=r(sum)*100


         qui drop keep proba
         local diff0=0
         qui gen proba=.
         qui count
         local nnew=r(N)
         di in gr "Number of studied response's patterns for the GH step: " in ye `nnew'
         di in gr "(" in ye %6.2f `sumproba0' in gr "% of the group 0 and " in ye %6.2f `sumproba1' in gr "% of the group 1)"
         local dixj=10
         forvalues i=1/`nnew' {
            local dix=floor(`nnew'/10)
            if mod(`i',`dix')==0 {
               if "`dixj'"!="10" {
                  di ".." _c
               }
               di "`dixj'%" _c
               local dixj=`dixj'+10
            }
            local int=1
            forvalues j=1/`nbitems' {
               qui su item`j' in `i'
               local rep=r(mean)
               local diff0=0
               local diff1=`d'[`j',1]
               local sum "1+exp(x-`diff1')"
               forvalues m=2/`=`nbmodat'-1' {
                  local diff`m'=`diff`=`m'-1''+`d'[`j',`m']
                  local sum "`sum'+exp(`m'*x-`diff`m'')"
               }
               local int "(`int'*exp(`rep'*x-`diff`rep''))/(`sum')"
            }
            qui su mean in `i'
            local mean=r(mean)
            qui gausshermite `int',mu(`mean') sigma(`=sqrt(`var')') display
            qui replace proba=r(int) in `i'
         }
      }
   }
   qui gen eff=.
   forvalues i=0/1 {
      qui replace eff=proba*`n`i'' if group==`i'
   }
   qui replace eff=proba
   qui keep item* eff group proba

   local p1=1/`n1'
   local p0=1/`n0'
   qui gen eff2=.
   qui replace eff2=floor(eff/`p1') if group==1
   qui replace eff2=floor(eff/`p0') if group==0
   qui replace eff=eff-eff2*(`p1'*group+`p0'*(1-group))
   qui su eff2 if group==1
   local aff1=r(sum)
   qui su eff2 if group==0
   local aff0=r(sum)

   local unaff1=`n1'-`aff1'
   local unaff0=`n0'-`aff0'
   qui gen efftmp=eff2
   qui gsort + group - eff
   qui replace eff2=eff2+1 in 1/`unaff0'
   qui gsort - group - eff
   qui replace eff2=eff2+1 in 1/`unaff1'

   qui drop if eff2==0
   gsort group item*
   qui expand eff2
   qui drop proba eff eff2
}

qui alpha item*
local alpha=r(alpha)
qui gen groupc=group-.5
if `nbmodat'==1 {
   qui gen i=_n

   tempname diff
   matrix `diff'=`dd''

   qui reshape long item, i(i)
   qui rename item rep
   qui rename _j item

   qui gen  offset=0
   forvalues i=1/`nbitems' {
      qui replace offset=-`diff'[1,`i'] if item==`i'
   }
   matrix est=(`gamma',`=sqrt(`var')')

   if "`gammafix'"=="" {
      constraint 1 _cons=`=ln(`var')'
      qui xtlogit rep groupc  ,nocons i(i) offset(offset) constraint(1)
   }
   else {
      qui gllamm   rep groupc, nocons i(i) offset(offset)  iterate(0) fam(bin) link(logit) from(est) copy
   }
   tempname b V
}
else {
   matrix `db'=`db''
   qui pcm item*, fixed(`db') covariates(groupc)  fixedmu fixedvar(`var')
}
tempname b V
matrix `b'=e(b)
matrix `V'=e(V)
local gammaest=`b'[1,1]
local se=`V'[1,1]^.5


di
di
di in gr "{hline 91}"
di _col(60)  "Estimation with the "
di _col(50)  "Cramer-Rao bound" _col(75) "classical formula"
di in gr "{hline 91}"
if "`gammafixed'"==""  {
   di in green "Estimated value of the group effect" _col(59) in ye  %7.2f `gammaest'
}
di in green "Estimation of the s.e. of the group effect" _col(59) in ye %7.2f `se'
di in green "Estimation of the variance of the group effect" _col(56) in ye %10.4f `=`se'^2'
local power=1-normal(1.96-`gamma'/`se')+normal(-1.96-`gamma'/`se')
local poweruni=1-normal(1.96-`gamma'/`se')
local clpower=normal(sqrt(`n1'*`gamma'^2/((`n1'/`n0'+1)*`var'))-1.96)
di in green "Estimation of the power" _col(60) in ye %6.4f `poweruni' _col(86) in ye %6.4f `clpower'
local clnsn=(`n1'/`n0'+1)/((`n1'/`n0')*(`gamma'/sqrt(`var'))^2)*(1.96+invnorm(`poweruni'))^2
di in green "Number of patients for a power of" %6.2f `=`poweruni'*100' "%" _col(59) in ye `n0' "/" `n1' _col(77) in ye %7.2f `clnsn' "/" %7.2f `=`clnsn'*`n1'/`n0''
local ratio=(`n0'+`n1')/(`clnsn'*(1+`n1'/`n0'))
di in green "Ratio of the number of patients" in ye %6.2f _col(68)`ratio'
if `expectedpower'!=-1 {
   qui sampsi `=-`gamma'/2' `=`gamma'/2', sd1(`=sqrt(`var')') sd2(`=sqrt(`var')') alpha(0.05) power(`expectedpower') ratio(`=`n1'/`n0'')
   local expn_1=r(N_1)
   local expn_2=r(N_2)
   local expn2=`expn_1'*`ratio'
   di in green "Number of patients for a power of" %6.2f `=`expectedpower'*100' "%" _col(51) in ye %7.2f `expn2' "/" %7.2f `=`expn2'*`n1'/`n0'' _col(77) in ye %7.2f `expn_1' "/" %7.2f `expn_2'
}
di in gr "{hline 91}"
return scalar EstGamma=`gammaest'
return scalar CRbound=`=`se'^2'
return scalar CRPower=`poweruni'
return scalar ClPower=`clpower'
return scalar ClSS=`clnsn'
return scalar Ratio=`ratio'
return scalar CronbachAlpha=`alpha'



capture qui use `raschpowerfile',clear

end
