/* _gtvor.ado  11-21-2000
By David Kantor, Institute for Policy Studies, Johns Hopkins University.
This is a user-added feature for Stata's egen command.
As such, it goes in c:\ado rather than c:\stata\ado\_.

This provides a three-valued logic OR operation in an egen context.
This is the column-wise version.  See _rgtvor for the row-wise version.

This is part of a suite of three-valued logic egen utilities:
 tvnot, rtvor, rtvand, tvor, tvand.
(There are also tvlnot, tvlor, & tvland.  Those are earlier, less complete
versions, which stand as separate programs; they are not egen utilities.
These egen utilities are to be preferred.)

The binary operation utilities (rtvor, rtvand) actually take an arbitrary
number of arguments.  The column-wise "binary" operations (tvor, tvand)
also do the same, with the understanding that the arguments are the values
from one or more observations.

This borrows ideas from c:\stata\ado\_\_gmax.ado and _gcount.ado.

2-28-2001:  I am adding the "liberal" option.  This allows a different
version of the operation; it takes the OR of all non-missing elements, and
only yields missing if all arguments are missing.

*/

program define _gtvor
*! version 1.1.0  2-28-2001

version 5.0


if "`1'" == " " {
local typ1 "byte"
}
else {
local typ1 ""
}
/* We use typ1 to force a type of byte as a default.
egen sends a value of one single space if the type was not specified.
*/

local varlist "req new max(1)"
local exp "req nopre"
local if "opt"
local in "opt"
local options "by(string) LIBeral"
parse "`typ1' `*'"
tempvar touse x numfals numtrue nummis
/* Note that here, "true" is nonzero & nonmissing. */
quietly {
	gen byte `touse'=1 `if' `in'
	gen double `x'=`exp'
	sort `touse' `by'
	by `touse' `by': gen long `numfals' = sum((`x')==0) if `touse'==1
	by `touse' `by': replace  `numfals' = `numfals'[_N]
	by `touse' `by': gen long `numtrue' = sum((`x')~=0 & (`x')~=.) if `touse'==1
	by `touse' `by': replace  `numtrue' = `numtrue'[_N]
	by `touse' `by': gen long `nummis'  = sum((`x')==.) if `touse'==1
	by `touse' `by': replace  `nummis'  = `nummis'[_N]
	/*
	assert `numfals' >=0 & `numfals' ~=. if `touse'==1
	assert `numtrue' >=0 & `numtrue' ~=. if `touse'==1
	assert `nummis' >=0 & `nummis' ~=.  if `touse'==1
	*/

	#delimit ;
	if "`liberal'" =="liberal" {;
		by `touse' `by': replace `varlist'=
		 cond(`numtrue'==0 & `numfals'== 0, ., `numtrue' >0)
		 if `touse'==1;
	};
	else {;
		by `touse' `by': replace `varlist'=
		 cond(`numtrue' > 0, 1,
		   cond(`nummis' ==0, 0, .)
		 ) if `touse'==1;
	};
};
end;