*! Version 2.7 6October2005
*! Jean-Benoit Hardouin
************************************************************************************************************
* Stata program : clv
* Clustering of variables around latent variables
* Version 2.7 : October 6, 2005 /*return, multiple graphs, polychoric+consolidation*/
*
* Historic
* Version 1 (2005-06-11): Jean-Benoit Hardouin
* Version 1.1 (2005-07-07): Jean-Benoit Hardouin /*small bug in the consolidation process with cluster of only one variable*/
* Version 1.2 (2005-07-08): Jean-Benoit Hardouin /*Bug in the consolidation procedure when there is negative correlation*/
* Version 2 (2005-09-03): Jean-Benoit Hardouin /*Horizontal dendrograms (with Stata 9)*/
* Version 2.1 (2005-09-08): Jean-Benoit Hardouin /*More flexibility to abbreviate the names of the variables (with Stata 9)*/
* Version 2.1.1 (2005-09-08): Jean-Benoit Hardouin /*Integration of some requests of Ronan Conroy*/
* Version 2.1.2 (2005-09-08): Jean-Benoit Hardouin /*Possibility to give a title and an X/Y caption*/
* Version 2.2 (2005-09-11): Jean-Benoit Hardouin /*Kernel option*/
* Version 2.3 (2005-09-12): Jean-Benoit Hardouin /*Polychoric option*/
* Version 2.4 (2005-09-13): Jean-Benoit Hardouin /*v2 option*/
* Version 2.5 (2005-09-21): Jean-Benoit Hardouin /*corrections*/
* Version 2.6 (2005-10-02): Jean-Benoit Hardouin /*centroid method, biplot*/
*
* Jean-benoit Hardouin, Regional Health Observatory of Orléans - France
* jean-benoit.hardouin@orscentre.org
*
* News about this program : http://anaqol.free.fr
* FreeIRT Project : http://freeirt.free.fr
*
* Copyright 2005 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 clv,rclass
version 9.0
syntax [varlist(default=none)] [if] [in] [, CUTnumber(int 30) bar CONSolidation(int 0) noDENdro noSTANDardized deltaT HORizontal SHOWcount ABBrev(int 14) TITle(string) CAPtion(string) KERnel(numlist) METHod(string) noBIPlot ADDvar]
preserve
tempfile clvfile
qui save `clvfile',replace
local matsize=c(matsize)
local none=0
if "`varlist'"=="" {
*set trace on
   capture confirm matrix r(vp)
   if _rc==0 {
      capture confirm matrix r(matclus)
      if _rc ==0 {
         local none=1
      }
   }
   if `none'==0 {
      di in red "You cannot use the {hi:clv} command without {hi:varlist} if you have not already run {hi:clv}"
      error 198
      exit
   }
}

tempname matclus vp

if `none'==1 {
   matrix `vp'=r(vp)
   matrix `matclus'=r(matclus)
   local varlist `r(varlist)'
   tokenize `varlist'
   local nbitems=rowsof(`matclus')
   if "`method'"!="" {
      di in green "The {hi:method} option can not be modified without specification of the varlist. {hi:method} is omitted."
   }
   local method `r(method)'
   local kernel `r(kernel)'
/*
   if "`method'"=="polychoric" {
      di in red "The {hi:consolidation} is not possible with the {hi:polychoric} option"
      error 198
      exit
   }
*/
}
if "`method'"=="" {
   local method classical
}
if ("`method'"=="polychoric"|"`method'"=="polychoricv2")&"`standardized'"!="" {
   di in green "Initial variables are used with the {hi:polychoric} methods"
   di in green "But the procedure is based on the matrix of the polychoric correlations"
   di
}
if "`method'"!="classical"&"`method'"!="v2"&"`method'"!="centroid"&"`method'"!="polychoric"&"`method'"!="polychoricv2" {
   di in red "The {hi:method} `method' is unknown"
   error 198
   exit
}

tokenize `varlist'
local nbitems : word count `varlist'
marksample touse
qui keep if `touse'

local mat=max(`matsize',`=`nbitems'*2')
qui set matsize `mat'

if `nbitems'<3&`none'!=1 {
   di in red "You need at least 3 variables"
   error 198
   exit
}
forvalues i=1/`nbitems'{
   local label`i':variable label ``i''
   if "`label`i''"=="" {
      local label`i' ``i''
   }
   if "`method'"!="polychoric"&"`method'"!="polychoricv2" {
      qui su ``i''
      local mean=r(mean)
      if "`standardized'"=="" {
         local sd=r(sd)
      }
      else {
         local sd=1
      }
      qui replace ``i''=(``i''-`mean')/`sd'
   }
}

tempfile clvfiletmp
qui save `clvfiletmp',replace

qui count
local nbind=r(N)

local cons=`consolidation'

if "`method'"!="polychoric"&"`method'"!="polychoricv2" {
   local totvar=0
   forvalues i=1/`nbitems' {
      qui su ``i''
      local totvar=`totvar'+`r(Var)'
   }
}
else {
   local totvar `nbitems'
}
local nbkerk=0
local nbkerg=0

if "`kernel'"!="" {
   local nbkerg:word count `kernel'
   local fin0=0
   forvalues i=1/`nbkerg' {
      local nbi`i':word `i' of `kernel'
      local nbkerk=`nbkerk'+`nbi`i''
      local deb`i'=`fin`=`i'-1''+1
      local fin`i'=`deb`i''+`nbi`i''-1
      local list`i'
      forvalues j=`deb`i''/`fin`i'' {
         local list`i' `list`i'' ``j''
      }
   }
   tempname kerclus
   matrix `kerclus'=J(`=`nbkerk'-`nbkerg'',3,0)
   local ligne=1
   forvalues g=1/`nbkerg' {
       matrix `kerclus'[`ligne',1]=`nbitems'+`ligne'
       matrix `kerclus'[`ligne',2]=`deb`g''
       matrix `kerclus'[`ligne',3]=`deb`g''+1
       local clus`g'=`nbitems'+`ligne'
       local ligne=`ligne'+1
       if `nbi`g''>2 {
          forvalues i=2/`=`nbi`g''-1' {
             matrix `kerclus'[`ligne',1]=`nbitems'+`ligne'
             matrix `kerclus'[`ligne',2]=`deb`g''+`i'
             matrix `kerclus'[`ligne',3]=`nbitems'+`ligne'-1
             local clus`g'=`nbitems'+`ligne'
             local ligne=`ligne'+1
          }
      }
   }
}
if `nbitems'<`nbkerk' {
   di in red "You cannot define more variables in the {hi:kernel} option than items in the {hi:varlist}"
   error 198
   exit
}
di
di in green "{hline 30}"
di in green "TOTAL VARIANCE: " in ye %14.3f `totvar'
di in green "NUMBER OF INDIVIDUALS: " in ye %7.0f `nbind'
di in green "METHOD:" in ye _col(`=31-length("`method'")') "`=upper("`method'")'"
di in green "{hline 30}"
di
if "`kernel'"!="" {
   forvalues i=1/`nbkerg' {
      di in green "The kernel numbered " in ye `clus`i'' in green " is composed of `nbi`i'' variables: " in ye "`list`i''"
      di
   }
}
else {
   local nbkerk=0
   local nbkerg=0
}
tempname Ev
if `none'!=1 {
   matrix `matclus'=J(`nbitems',`nbitems',0)
   matrix `vp'=J(`=2*`nbitems'-1',10,0)
   forvalues i=1/`nbitems' {
      matrix `matclus'[`i',1]=`i'
      if "`method'"!="polychoric"&"`method'"!="polychoric" {
         qui su ``i''
         matrix `vp'[`i',1]=r(Var)
      }
      else {
         matrix `vp'[`i',1]=1
      }
      matrix `vp'[`i',8]=`i'
      matrix `vp'[`i',9]=`totvar'
      matrix `vp'[`i',10]=100
   }
   matrix `vp'[`nbitems',3]=`nbitems'
   if "`method'"=="centroid" {
      local crit G
      di in green "{hline 89}"
      di in green _col(7) "Number of" _col(69) "`crit'" _col(71) "Explained" _col(82) "Relative"
      di in green "Step" _col(8) "clusters" _col(20) "Child 1" _col(33) "Child 2" _col(46) "Parent" _col(53) "`crit' value" _col(61) "variation" _col(72) "Variance"  _col(81) "Variation"
      di in green "{hline 89}"
   }
   else {
      local crit T
      di in green "{hline 100}"
      if "`method'"=="v2"|"`method'"=="polychoricv2" {
         di in green _col(84) "Maximal"
      }
      else {
         di in green _col(84) "Current"
      }
      di in green _col(7) "Number of" _col(69) "`crit'" _col(71) "Explained" _col(85) "Second" _col(93) "Relative"
      di in green "Step" _col(8) "clusters" _col(20) "Child 1" _col(33) "Child 2" _col(46) "Parent" _col(53) "`crit' value" _col(61) "variation" _col(72) "Variance" _col(81) "Eigenvalue" _col(92) "Variation"
      di in green "{hline 100}"
   }
   tempname threshold
   matrix `threshold'=J(`nbitems',3,0)
   forvalues i=1/`=`nbitems'-1' {
      local clus=`nbitems'+`i'
      local minegenval=999999
      local minegenval2=999999
      forvalues k=1/`=`clus'-1' {
         local list`k'
         local numlist`k'
         forvalues j=1/`clus' {
            if (`matclus'[`j',`i']==`k') {
               local list`k' `list`k'' ``j''
               local numlist`k' `numlist`k'' `j'
            }
         }
      }
      if `clus'>`nbitems'+`nbkerk'-`nbkerg' {
         if "`method'"=="centroid" {
            tempname centrj centrk diffjk
         }
         forvalues j=1/`clus' {
            local nblistj:word count `list`j''
            forvalues k=`=`j'+1'/`clus' {
               local nblistk:word count `list`k''
               if `nblistj'!=0&`nblistk'!=0 {
                  if "`method'"=="centroid" {
                     qui genscore `list`j'',score(`centrj') mean
                     qui su `centrj'
                     local Varj=r(Var)
                     qui genscore `list`k'',score(`centrk') mean
                     qui su `centrk'
                     local Vark=r(Var)
                     qui gen `diffjk'=`centrk'-`centrj'
                     qui su `diffjk'
                     local Varjk=r(Var)
                     drop `centrj' `centrk' `diffjk'
                     local ev=(`nblistj'*`nblistk')/(`nblistj'+`nblistk')*`Varjk'
                     if `ev'<`minegenval' {
                        local minegenval=`ev'
                        local minj `j'
                        local mink `k'
                        local eigen=0
                        local eigen2=0
                     }
                  }
                  else {
                     if "`method'"=="classical"|"`method'"=="v2" {
                        qui pca `list`j'' `list`k'',cov
                        matrix `Ev'=e(Ev)
                     }
                     else if "`method'"=="polychoric"|"`method'"=="polychoricv2" {
                        qui polychoricpca `list`j'' `list`k''
                        matrix `Ev'=r(eigenvalues)
                     }
                     local lambda1=`Ev'[1,1]
                     local lambda2=`Ev'[1,2]
                     local ev=`vp'[`j',1]+`vp'[`k',1]-`lambda1'
/*
                     local t1=`vp'[`j',1]
                     local t2=`vp'[`k',1]
                     di "`ev'=`t1'+`t2'-`lambda1'"
*/
                     local ev2=max(`vp'[`j',5],`vp'[`k',5],`lambda2')
                     if ("`method'"=="v2"|"`method'"=="polychoricv2")&`ev'<`minegenval' {
                        local minegenval=`ev'
                        local eigen=`lambda1'
                        local minj `j'
                        local mink `k'
                        local eigen2=`lambda2'
                     }
                     else if ("`method'"=="classical"|"`method'"=="polychoric")&`ev2'<`minegenval2' {
                        local minegenval=`ev'
                        local minegenval2=`ev2'
                        local eigen=`lambda1'
                        local minj `j'
                        local mink `k'
                        local eigen2=`ev2'
                     }
                  }
               }
            }
         }
      }
      else {
         local ligne=`clus'-`nbitems'
         local j=`kerclus'[`ligne',2]
         local k=`kerclus'[`ligne',3]
         if "`method'"!="centroid" {
            if "`method'"=="classical"|"`method'"=="v2" {
               qui pca `list`j'' `list`k'',cov
               matrix `Ev'=e(Ev)
            }
            else if "`method'"=="polychoric"|"`method'"=="polychoricv2"{
               qui polychoricpca `list`j'' `list`k''
               matrix `Ev'=r(eigenvalues)
            }
            local lambda1=`Ev'[1,1]
            local lambda2=`Ev'[1,2]
            local ev=`vp'[`j',1]+`vp'[`k',1]-`lambda1'
            local minegenval=`ev'
            local eigen=`lambda1'
            local minj `j'
            local mink `k'
            local eigen2=`lambda2'
         }
         else if "`method'"=="centroid" {
            local nblistj:word count `list`j''
            local nblistk:word count `list`k''
            tempname v1 v2 v12
            qui genscore `list`j'',score(`v1') mean
            qui genscore `list`k'',score(`v2') mean
            qui gen `v12'=`v1'-`v2'
            qui su `v12'
            local varj=r(Var)
            local minegenval=(`nblistj'*`nblistk')/(`nblistj'+`nblistk')*`varj'
            local minj `j'
            local mink `k'
         }
      }
      if `minj'<=`nbitems' {
         local nomj=abbrev("``minj''",14)
      }
      else {
         local nomj `minj'
      }
      *set trace off
      if `mink'<=`nbitems' {
         local nomk=abbrev("``mink''",14)
      }
      else {
         local nomk `mink'
      }
      forvalues j=1/`nbitems' {
         matrix `matclus'[`j',`=`i'+1']=`matclus'[`j',`i']
      }
      if "`method'"!="centroid" {
         matrix `vp'[`clus',1]=`eigen'                            /*FIRST EIGEN VALUE OF THE NEW CLUSTER*/
         matrix `vp'[`clus',2]=`minegenval'                       /*VARIATION OF THE T CRITERION*/
         matrix `vp'[`clus',3]=`vp'[`=`clus'-1',3]-`vp'[`clus',2] /*T CRITERION*/
         matrix `vp'[`clus',4]=`vp'[`clus',2]/`vp'[`=`clus'-1',3] /*RELATIVE VARIATION OF THE T CRITERION*/
         matrix `vp'[`clus',5]=`eigen2'                           /*SECOND EIGEN VALUE OF THE NEW CLUSTER*/
         matrix `vp'[`clus',6]=`minj'                             /*CHILD 1*/
         matrix `vp'[`clus',7]=`mink'                             /*CHILD 2*/
         matrix `vp'[`clus',8]=`nbitems'+`i'                      /*NUMBER OF THE NEW CLUSTER*/
         matrix `vp'[`clus',9]=`vp'[`=`clus'-1',9]-`minegenval'   /*EXPLAINED VARIANCE*/
         matrix `vp'[`clus',10]=`vp'[`clus',9]/`totvar'*100       /*% OF EXPLAINED VARIANCE*/
      }
      else {
         matrix `vp'[`clus',1]=0                                  /*FIRST EIGEN VALUE OF THE NEW CLUSTER*/
         matrix `vp'[`clus',2]=`minegenval'                       /*VARIATION OF THE G CRITERION*/
         matrix `vp'[`clus',3]=`vp'[`=`clus'-1',3]-`vp'[`clus',2] /*G CRITERION*/
         matrix `vp'[`clus',4]=`vp'[`clus',2]/`vp'[`=`clus'-1',3] /*RELATIVE VARIATION OF THE T CRITERION*/
         matrix `vp'[`clus',5]=0                                  /*SECOND EIGEN VALUE OF THE NEW CLUSTER*/
         matrix `vp'[`clus',6]=`minj'                             /*CHILD 1*/
         matrix `vp'[`clus',7]=`mink'                             /*CHILD 2*/
         matrix `vp'[`clus',8]=`nbitems'+`i'                      /*NUMBER OF THE NEW CLUSTER*/
         matrix `vp'[`clus',9]=`vp'[`=`clus'-1',9]-`minegenval'   /*EXPLAINED VARIANCE*/
         matrix `vp'[`clus',10]=`vp'[`clus',9]/`totvar'*100       /*% OF EXPLAINED VARIANCE*/
      }
      foreach j of numlist `numlist`minj'' `numlist`mink''  {
         matrix `matclus'[`j',`=`i'+1']=`clus'
      }
      if "`kernel'"!=""&`i'==`=`nbkerk'-`nbkerg'+1' {
         local T=`vp'[`=`clus'-1',9]
         di _col(0) in ye "init" _col(12) %4.0f `=`nbitems'-`nbkerk'+`nbkerg'' _col(52) %8.4f `T' _col(62) %8.4f `=`totvar'-`T'' _col(72) %7.3f `=`T'/`totvar'*100' "%"
      }
      if `clus'>`nbitems'+`nbkerk'-`nbkerg' {
         if  `clus'==`nbitems'+`nbkerk'-`nbkerg'+1 {
            local relv
            local percent
         }
         else {
            local relv=(`minegenval'-`vp'[`=`clus'-1',2])/`vp'[`=`clus'-1',3]*100
            local percent %
            matrix `threshold'[`=`nbitems'-`i'+1',1]=`relv'
            matrix `threshold'[`=`nbitems'-`i'+1',3]=`minegenval'
            if `i'>1 {
               matrix `threshold'[`=`nbitems'-`i'+1',2]=`relv'-`threshold'[`=`nbitems'-`i'+2',1]
            }
         }
         if "`method'"=="centroid" {
            di _col(0) in ye %4.0f `=`i'-`nbkerk'+`nbkerg'' _col(12) %4.0f `=`nbitems'-`i'' _col(20) "`nomj'" _col(33) "`nomk'" _col(45) %7.0f `=`i'+`nbitems'' _col(52) %8.4f `vp'[`clus',9] _col(62) %8.4f `minegenval' _col(72) %7.3f `vp'[`clus',10] "%" _col(83) _col(84) %5.2f `relv' "`percent'"
         }
         else {
            di _col(0) in ye %4.0f `=`i'-`nbkerk'+`nbkerg'' _col(12) %4.0f `=`nbitems'-`i'' _col(20) "`nomj'" _col(33) "`nomk'" _col(45) %7.0f `=`i'+`nbitems'' _col(52) %8.4f `vp'[`clus',9] _col(62) %8.4f `minegenval' _col(72) %7.3f `vp'[`clus',10] "%" _col(83) %8.4f `vp'[`clus',5] _col(95) %5.2f `relv' "`percent'"
         }
      }
   }
   local i=2*`nbitems'-1
   local relv=(`vp'[`i',3]-`vp'[`i',2])/`vp'[`i',3]*100
   if "`method'"=="centroid" {
      di in ye _col(84) %5.2f `relv' "`percent'"
   }
   else {
      di in ye _col(95) %5.2f `relv' "`percent'"
   }
   matrix `threshold'[1,1]=`relv'
   matrix `threshold'[1,2]=`relv'-`threshold'[2,1]
   matrix `threshold'[1,3]=`vp'[`i',3]
   *matrix list `threshold'
   local best=0
   local maxbest=0
   local best2=0
   local maxbest2=0
   forvalues i=1/`nbitems' {
      if `threshold'[`i',3]>`maxbest2' {
         if `threshold'[`i',3]>`maxbest' {
            local maxbest2=`maxbest'
            local best2=`best'
            local maxbest=`threshold'[`i',3]
            local best=`i'
         }
         else {
            local maxbest2=`threshold'[`i',3]
            local best2=`i'
         }
      }
   }
   di in green "{hline 100}"
   di in green "Proposed best partitions: "
   di in green "Based on the variation of the T criterion"
   di in green _col(10) "1. Partitions in " in ye `best' in green " clusters"
   di in green _col(10) "2. Partitions in " in ye `best2' in green " clusters"
   return local bestvariation `best' `best2'
   local bestt=0
   local bestt2=0
   local var=0
   local var2=0
   forvalues i=1/`nbitems' {
       if `threshold'[`i',2]>`var2'&`i'<`nbitems'-1 {
           if `threshold'[`i',2]>`var' {
              local bestt2=`bestt'
              local var2=`var'
              local var=`threshold'[`i',2]
              local bestt=`i'
           }
           else {
              local var2=`threshold'[`i',2]
              local bestt2=`i'
           }
       }
   }
   di in green "Based on a research of a threshold"
   di in green _col(10) "1. Partitions in " in ye `bestt' in green " clusters"
   di in green _col(10) "2. Partitions in " in ye `bestt2' in green " clusters"
   forvalues i=`=`nbitems'+1'/`=`nbitems'+`nbkerk'-`nbkerg'' {
      matrix `vp'[`i',2]=`totvar'-`T'
      matrix `vp'[`i',9]=`T'
      matrix `vp'[`i',10]=`T'/`nbitems'*100
   }
   return local bestthresold `bestt' `bestt2'
}

if "`bar'"!="" {
   drop _all
   qui set obs `nbitems'
   qui svmat `vp' ,names(v)
   qui drop in 1/`nbitems'
   qui gen id=`nbitems'-_n
   qui drop if id>`nbitems'-`nbkerk'+`nbkerg'-1
   label variable id "Number of clusters"
   label variable v2 "T variation"
   graph twoway bar v2 id, name(bar,replace) vert ,ylabel(0(0.5)2) xlabel(1(1)`=`nbitems'-`nbkerk'+`nbkerg'-1')
}

drop _all
qui set obs `nbitems'
qui svmat `matclus' ,names(v)
local listorder
forvalues i=`nbitems'(-1)1 {
   local listorder `listorder' v`i'
}
qui gen id=_n
qui sort `listorder'

capture cluster delete clv,zap
qui cluster complete v* ,name(clv)

qui replace clv_id=_n
qui replace clv_ord=id
qui replace clv_hgt=.

qui  gen fait=0
qui gen clus=0
forvalues i=2/`nbitems' {
   local ligne=`nbitems'+`i'-1
   if (`vp'[`ligne',6]<=`nbitems') {
      local first=`vp'[`ligne',6]
      gsort +fait -v`i'  +clv_id
   }
   else {
      local first=`vp'[`ligne',7]
      gsort +fait -v`i'  +clv_id
   }
   if "`deltaT'"!="" {
      qui replace clv_hgt=`vp'[`ligne',2] in 1
   }
   else {
      qui replace clv_hgt=100-`vp'[`ligne',10] in 1
   }
   qui replace fait=1 in 1
   qui replace clus=`vp'[`ligne',8] in 1
}
qui gen label=""
forvalues i=1/`nbitems' {
   qui replace label=abbrev("`label`i''",`abbrev') if clv_id==`i'
}
sort clv_id
if `nbitems'>`cutnumber' {
   local var "Groups of variables"
   local cut cutnumber(`cutnumber') /*labcutn*/
}
else {
   local var "Variables"
   local cut label(label)
}
qui su clv_hgt
local tmp=r(max)
local max=floor(`tmp')+.5
if `tmp'>`max' {
   local max=`max'+.5
}
local maxvar=`max'+5
if "`dendro'"=="" {
   if "`title'"=="" {
      local title "Clustering around Latent Variables (CLV)"
   }
   if "`caption'"!="" {
      local var "`caption'"
   }
   if "`deltaT'"!="" {
      local titleL "Variation of the T criterion"
      local yl "0(.5)`max'"
   }
   else {
      local titleL "% Unexplained Variance"
      local yl "0(25)`maxvar'"
   }
   if "`horizontal'"!="" {
      cluster dendro clv,  name (dendrogram,replace) hor ytitle("`var'") `showcount' xtitle("`titleL'") title("`title'",span) xlabel(`yl') ylabel(,angle(0)) `cut'
   }
   else {
      cluster dendro clv, name(dendrogram,replace)  xtitle("`var'") `showcount' ytitle("`titleL'") title("`title'",span) ylabel(`yl') `cut'
   }
}

if `cons'>`nbitems'-`nbkerk'+`nbkerg' {
   di in ye "The {hi:consolidation} is not possible for a number of clusters superior to the initial number of clusters"
   local cons=0
}

/*
if `cons'!=0&("`method'"=="polychoric"|"`method'"=="polychoricv2") {
   di in ye "The {hi:consolidation} is not possible with the {hi:polychoric} methods"
   local cons=0
} 
*/

if `cons'!=0 {
   sort v`=`nbitems'-`cons'+1'
   gen cut`cons'=1
   local g=1
   forvalues i=2/`nbitems' {
      if v`=`nbitems'-`cons'+1'[`i']!=v`=`nbitems'-`cons'+1'[`=`i'-1'] {
         local g=`g'+1
      }
      qui replace cut`cons'=`g' in `i'
   }
   sort id
   tempname group
   mkmat cut`cons',matrix(`group')

   *cluster generate cut = groups(2/9) , name(clv)
   use `clvfiletmp',replace

   local n=1
   local env=1
   while (`env'==1) {
      forvalues g=1/`cons' {
         local list`g'
         forvalues i=1/`nbitems' {
            if `group'[`i',1]==`g' {
               local list`g' `list`g'' ``i''
            }
         }
      }
      di
      if `n'==1 {
         di in green "{hline 30}"
         di in green "PARTITION BEFORE CONSOLIDATION"
         di in green "{hline 30}"
      }
      di
      local col=1
      local max=0
      *set trace on
      local critT=0
      forvalues g=1/`cons' {
         di _col(`col') in green "GROUP " %2.0f `g' _c
         local col=`col'+10
         local tmp`g':word count `list`g''
         if `tmp`g''>`max' {
            local max `tmp`g''
         }
         tempvar f1`g'
         if "`method'"=="centroid" {
               qui genscore `list`g'',score(`f1`g'') mean
               qui su `f1`g''
               local var=r(Var)
               local critT=`critT'+`tmp`g''*`var'
         }
         else {
            if `tmp`g''>1 {
               if "`method'"=="classical"|"`method'"=="v2" {
                  qui pca `list`g'',cov
                  matrix `Ev'=e(Ev)
                  qui predict `f1`g''
               }
               else if "`method'"=="polychoric"|"`method'"=="polychoric" {
                  qui polychoricpca `list`g'',score(`f1`g'') nscore(1)
                  matrix `Ev'=r(eigenvalues)
                  rename `f1`g''1 `f1`g''
               }
               local lambda1=`Ev'[1,1]
               local critT=`critT'+`lambda1'
            }
            else {
               qui gen `f1`g''=`list`g''
               if "`standardized'"=="" {
                   local critT=`critT'+1
               }
               else  {
                  qui su
                  local critT=`critT'+`r(Var)'
               }
            }
         }
      }
      di
      forvalues i=1/`max' {
         local col=1
         forvalues g=1/`cons' {
            local tmpv:word `i' of `list`g''
            local tmpv=abbrev("`tmpv'",8)
            di _col(`col') in ye %8s "`tmpv'"  _c
            local col= `col'+10
         }
         di
      }
      di
      di in green "Variance Explained : " in ye %6.3f  `=`critT'/`totvar'*100' in green "%"
      di in green "T criterion : " in ye %6.4f  `critT'
      di
      di in green "{hline 21}"
      di in green "CONSOLIDATION: STEP `n'"
      di in green "{hline 21}"
      local n=`n'+1
      local env=0
      if "`method'"=="polychoric"|"`method'"=="polychoricv2" {
         local command polychoric
      }
      else {
         local command corr
      }
      forvalues i=1/`nbitems' {
         local env`i'=0
         local gr=`group'[`i',1]
         qui `command' ``i'' `f1`gr''
         local corr`i'=r(rho)
         local corrs`i'=r(rho)
         forvalues g=1/`cons' {
            qui `command' ``i'' `f1`g''
            local tmpcorr=r(rho)
            if ((`corr`i'')<(`tmpcorr')&"`method'"=="centroid")|((`corr`i'')^2<(`tmpcorr')^2& "`method'"!="centroid") {
               local env=1
               local env`i'=1
               matrix `group'[`i',1]=`g'
               local corr`i'=`tmpcorr'
            }
         }
         if `env`i''==1 {
            local g=`group'[`i',1]
            di in green  "The variable " in ye "``i'' " in green "is assigned to the `g'th group" _c
            if "`method'"!="centroid" {
               di in green " (corr^2=" %6.4f in ye  (`corr`i'')^2 in green " vs " in ye %6.4f (`corrs`i'')^2 in green ")"
            }
            else {
               di in green " (corr=" %6.4f in ye  (`corr`i'') in green " vs " in ye %6.4f (`corrs`i'') in green ")"
            }

         }
      }
      if `env'==0 {
         local latent
         forvalues g=1/`cons' {
             label variable `f1`g'' "Latent variable `g'"
             local latent `latent' `f1`g''
             return local cluster`g' `list`g''
         }
         matrix `group'=`group''
         matrix colnames `group'=`varlist'
         return matrix affect=`group'
         di in ye "Stability of the partition is achieved"
         if `cons'<=7 {
            di
            di in green "{hline 42}"
            di in green "CORRELATION MATRIX OF THE LATENT VARIABLES"
            di in green "{hline 42}"
            di
            di in green "{hline `=(`cons')*13+15'}"
            forvalues g=1/`cons' {
               di _col(`=13*(`g'-1)+23') in green "Latent" _c
            }
            di
            forvalues g=1/`cons' {
               di _col(`=13*(`g'-1)+19') in green "variable `g'" _c
            }
            di
            di in green "{hline `=(`cons')*13+15'}"
            forvalues g=1/`cons' {
               di in green "Latent variable `g'" _c
               forvalues h=1/`cons' {
                  local loc=13*`h'+10
                  qui corr `f1`g'' `f1`h''
                  local rho=r(rho)
                  di _col(`loc') in ye %6.4f `rho' _c
               }
               di
            }
            di in green "{hline `=(`cons')*13+15'}"
            di
         }
         if `nbind'<=800&"`biplot'"=="" {
            local max=max(`matsize',`nbind')
            set matsize `max'
            if "`addvar'"!="" {
               local add `varlist'
            }
            qui biplotvlab `latent' `add', name(biplot,replace) norow colopts(name(latent variables)) alpha(0) title(Biplot of the latent variables) labdes(size(vsmall) color(blue)) stretch(1)
         }
         else {
            di in green "There is more than 800 individuals, so the {hi:biplot} is disabled"
         }
      }
      forvalues g=1/`cons' {
         drop `f1`g''
      }
   }
}
set matsize `matsize'
use `clvfile',replace
capture cluster delete clv,zap
return matrix vp=`vp'
return matrix matclus=`matclus'
return local varlist `varlist'
return local method `method'
return local kernel `kernel'
end
