*! distan.ado	version 1.0	12 March 1998
*! Command for calculating similarity and
*! dissimilarity measures between observations

program define distan
version 5.0
local varlist "required existing"
local options "STandar DIstan(string) AVerage SAve(string)"
parse "`*'"
local k: word count `varlist'
local n=_N
parse "`varlist'", parse(" ")
preserve

* Standarization of variables

if "`standar'" != "" {
	local var 1
	while `var' <= `k' {
		tempvar xx
		egen `xx' = std(``var''), mean(0) std(1)
		quietly replace ``var'' = `xx'
		drop `xx'
		local var = `var' + 1
	}
}

* Distance calculation

if "`save'" == "" { tempfile file }
else { local file "`save'" }
tempname disproc
postfile `disproc' elem1 elem2 distan using `file'
if substr("`distan'",1,2)=="co" {
	if substr("`distan'",1,3)=="cor" { display "Calculating correlations..." }
	else { display "Calculating covariances..." }
	local n1 1
	while `n1'<=`n' {
		local mean1 = 0.0
		local m1 0
		local var 1
		while `var'<=`k' {
			if ``var''[`n1']==. { local m1=`m1'+1 }
			else { local mean1=`mean1'+``var''[`n1'] }
			local var=`var'+1
		}
		local mean1=`mean1'/(`k'-`m1')
		if substr("`distan'",1,3)=="cor" {
			local s1 = 0.0
			local var 1
			while `var'<=`k' {
				if ``var''[`n1']!=. {
					local s1=`s1'+(``var''[`n1']-`mean1')^2
				}
				local var=`var'+1
			}
			local s1=sqrt(`s1'/(`k'-`m1'))
		}
		local n2 1
		while `n2'<=(`n'-`n1') {
			local xx=`n1'+`n2'
			local mean2 = 0.0
			local m2 0
			local s12 = 0.0
			local k12 0
			local var 1
			while `var'<=`k' {
				if ``var''[`xx']==. { local m2=`m2'+1 }
				else { local mean2=`mean2'+``var''[`xx'] }
				local var=`var'+1
			}
			local mean2=`mean2'/(`k'-`m2')
			local var 1
			while `var'<=`k' {
				if (``var''[`n1']!=. & ``var''[`xx']!=.) {
					#delimit ;
					local s12=`s12'+(``var''[`n1']-`mean1')*
					(``var''[`xx']-`mean2');
					#delimit cr
					local k12=`k12'+1
				}
				local var=`var'+1
			}
			local s12=`s12'/`k12'
			if substr("`distan'",1,3)=="cor" {
				local s2 = 0.0
				local var 1
				while `var'<=`k' {
					if ``var''[`xx']!=. {
						local s2=`s2'+(``var''[`xx']-`mean2')^2
					}
				local var=`var'+1
				}
				local s2=sqrt(`s2'/(`k'-`m2'))
				local s12=`s12'/(`s1'*`s2')
			}
			post `disproc' `n1' `xx' (`s12')
			local n2=`n2'+1
		}
		local n1=`n1'+1
	}
}
else {
	if substr("`distan'",1,2)=="ma" {
		local dim 1
		display "Calculating Manhattan Distance ..."
	}
	else if substr("`distan'",1,2)=="mi" {
		local ind1=index("`distan'","[")+1
		local ind2=index("`distan'","]")
		local dim=real(substr("`distan'",`ind1',`ind2'-`ind1'))
		display "Calculating Minkowski Distance. Dim=" "`dim'" " ..."
	}
	else {
		local dim 2
		display "Calculating Euclidian Distance..."
	}
	local n1 1
	while `n1'<=`n' {
		local n2 1
		while `n2'<=(`n'-`n1') {
			local xx=`n1'+`n2'
			local var 1
			local dist 0
			local k12 0
			while `var'<=`k' {
				if ``var''[`n1']!=. & ``var''[`xx']!=. {
					#delimit ;
					local dist=`dist'+abs(``var''[`n1']-
					``var''[`xx'])^(`dim');
					#delimit cr
					local k12=`k12'+1
				}
				local var=`var'+1
			}
			if `k12'==0 { local dist=. }
			else {
				if "`average'"=="" { local dist=`dist'^(1/`dim') }
				else { local dist=(`dist'/`k12')^(1/`dim') }
			}
			post `disproc' `n1' `xx' `dist'
			local n2=`n2'+1
		}
		local n1=`n1'+1
	}
}
postclose `disproc'
restore
end