%%%%%%%%%%%
% IVTAR.M %
%%%%%%%%%%%
% for questions, contact

% Bruce E. Hansen
% Department of Economics
% Social Science Building
% University of Wisconsin
% Madison, WI 53706-1393
% bhansen@ssc.wisc.edu
% http://www.ssc.wisc.edu/~bhansen/


% This is a MATLAB procedure.  It computes estimates and confidence
% intervals for threshold models with endogenous regressors.

% It computes the estimator described in
% "Instrumental Variable Estimation of a Threshold Model"
% written by Mehmet Caner and Bruce E. Hansen

% Be sure to have the Gauss graphics library active.

% If you run this program, it is currently set up to generate some simulated data 
% and estimate the model on this data.  
% For your own application, you can substitute your own data.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Example using Simulated Data %
function ivtar
n=100;
kx=4;
sig=[1 .5;.5 1];
e=normrnd(0,1,n,2)*chol(sig);
q=normrnd(0,1,n,1);
x=normrnd(0,1,n,kx);
z2=[ones(n,1),q];
z1=x*ones(kx,1).*3+e(:,2);
zz=(z1+z2*ones(2,1))*.1;
y=zz.*(q<0)-zz.*(q>0)+e(:,1);

qhat=gmm_thresh(y,z1,z2,x,q,.9,.8,1,1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% GMM_THRESH

% Computes threshold model with endogenous variables

% Format

% qhat = gmm_thresh(y,z1,z2,x,q,_conf,_conf1,_conf2,_reduced);

% Inputs
% y	nx1	dependent variable
% z1	nxk1	endogenous rhs variables
% z2	nxk2	exogenous rhs variables
% x	nxm	instrumental variables not included in z2, m>=k1
% q	nx1	threshold variable
% conf_	1x1	level for confidence interval for threshold, e.g. conf_=.9
% conf1_	1x1	confidence level for threshold interval used as input to slope intervals, e.g. conf2_=.8 
% conf2_	1x1	interval dummy - to determine method for threshold interval used as input to slope intervals
%		set to 0 for uncorrected (homoskedastic) interval
%		set to 1 for heteroskedastic correction by quadratic
%		set to 2 for heteroskedastic correction by nonparametric kernel
% reduced_	1x1	reduced form dummy
%		set to 0 if reduced form is linear (no threshold)
%		set to 1 if reduced form is a linear threshold model

% Output
% qhat	1x1	threshold estimate

% Most of the output is written to the screen.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function qhat=gmm_thresh(y,z1,z2,x,q,conf_,conf1_,conf2_,reduced_);
xx=[x,z2];
if reduced_==0
    z1hat=xx*regress(z1,xx);
else
    [z1hat,rhohat]=joint_thresh(z1,xx,q);
end;
zhat=[z1hat,z2];
[yhat,qhat,qcf0,qcf1,qcf2] = joint_thresh_ci(y,zhat,q,conf_,1);

z=[z1,z2];
da=(q<=qhat);
db=1-da;
ind=0;
for i=1:length(da)
    if da(i)==1
        if ind==0
            ya=y(i,:);
            xa=xx(i,:);
            za=z(i,:);
            ind=1;
        else
            ya=[ya;y(i,:)];
            xa=[xa;xx(i,:)];
            za=[za;z(i,:)];
        end;
    end;
end;
ind=0;
for i=1:length(db)
    if db(i)==1
        if ind==0
            yb=y(i,:);
            xb=xx(i,:);
            zb=z(i,:);
            ind=1;
        else
            yb=[yb;y(i,:)];
            xb=[xb;xx(i,:)];
            zb=[zb;z(i,:)];
        end;
    end;
end;

[beta1,se1,jstat1] = gmm_linear(ya,za,xa);
[beta2,se2,jstat2] = gmm_linear(yb,zb,xb);


beta1l=beta1-se1*1.96;
beta1u=beta1+se1*1.96;
beta2l=beta2-se2*1.96;
beta2u=beta2+se2*1.96;

[yhat,qhat,qcf0i,qcf1i,qcf2i] = joint_thresh_ci(y,zhat,q,conf1_,0);
if conf2_==0
    qcf=qcf0i;
elseif conf2_==1
    qcf=qcf1i;
elseif conf2_==2
    qcf=qcf2i;
end;
qq=unique(q);
qqcf2=(qq<=qcf(2));
ind=0;
for i=1:length(qqcf2)
    if qqcf2(i)==1
        if ind==0
            temp=qq(i);
            ind=1;
        else
            temp=[temp;qq(i)];
        end;
    end;
end;
qq=temp;
qqcf1=(qq>=qcf(1)); 
ind=0;
for i=1:length(qqcf1)
    if qqcf1(i)==1
        if ind==0
            temp=qq(i);
            ind=1;
        else
            temp=[temp;qq(i)];
        end;
    end;
end;
qq=temp;
clear qqcf1;
clear qqcf2;
ind=0;
i=1;
while i<=length(qq(:,1));
    qi=qq(i);
    dai=(q<=qi);
    dbi=1-dai;
    for ii=1:length(dai)
        if dai(ii)==1
            if ind==0
                ya=y(ii,:);
                xa=xx(ii,:);
                za=z(ii,:);
                ind=1;
            else
                ya=[ya;y(ii,:)];
                xa=[xa;xx(ii,:)];
                za=[za;z(ii,:)];
            end;
        end;
    end;
    ind=0;
    for ii=1:length(dbi)
        if dbi(ii)==1
            if ind==0
                yb=y(ii,:);
                xb=xx(ii,:);
                zb=z(ii,:);
                ind=1;
            else
                yb=[yb;y(ii,:)];
                xb=[xb;xx(ii,:)];
                zb=[zb;z(ii,:)];
            end;
        end;
    end;
    [beta1i,se1i,jstat1i] = gmm_linear(ya,za,xa);
    [beta2i,se2i,jstat2i] = gmm_linear(yb,zb,xb);
    beta1l=min([(beta1i-se1i*1.96),beta1l]')';
    beta1u=max([(beta1i+se1i*1.96),beta1u]')';
    beta2l=min([(beta2i-se2i*1.96),beta2l]')';
    beta2u=max([(beta2i+se2i*1.96),beta2u]')';
    i=i+1;
end;
disp(' ');
disp(' ');
fprintf('Threshold Estimate:                       %f\n',qhat);
fprintf('Confidence Interval - Uncorrected:        %f  %f\n',qcf0(1),qcf0(2));
fprintf('Confidence Interval - Het Corrected Quad: %f  %f\n',qcf1(1),qcf1(2));
fprintf('Confidence Interval - Het Corrected NP:   %f  %f\n',qcf2(1),qcf2(2));
disp(' ');
disp(' ');
fprintf('Regime 1 : Threshold variable less than %f\n',qhat);
fprintf('Number of observations:                   %f\n',sum(da));
disp(' ');
disp('         Estimates          S.E.          Lower');
for i=1:length(se2)
    fprintf('%f    %f     %f    %f\n',beta1(i),se1(i),beta1l(i),beta1u(i));
end;
disp(' ');
fprintf('Regime 2 : Threshold variable greater than %f\n',qhat);
fprintf('Number of observations:                   %f\n',sum(db));
disp(' ');
disp('         Estimates          S.E.          Lower');
for i=1:length(se2)
    fprintf('%f    %f     %f    %f\n',beta2(i),se2(i),beta2l(i),beta2u(i));
end;
disp(' ');


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% JOINT_THRESH

% Estimates the threshold in a multivariate threshold model

% Format
% [yhat,qhat] = joint_thresh(y,x,q);

% Inputs
% y	nxm	dependent variable(s)
% x	nxk	independent variables (should include constant)
% q	nx1	threshold variable

% Outputs
% yhat	nxm	Predicted values for y
% qhat	1x1	Threshold Estimate 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [yhat,qhat]=joint_thresh(y,x,q);
n=length(y(:,1));
k=length(y(1,:));
e=y-x*regress(y,x);
s0=det(e'*e);
n1=round(.05*n)+k;
n2=round(.95*n)-k;
qs=sortrows(q,1);
qs=qs(n1:n2);
qs=unique(qs);
qn=length(qs(:,1));
sn=zeros(qn,1);
r=1;
while r<=qn
    d=(q<=qs(r));
    xx=x.*(d*ones(1,length(x(1,:))));
    xx=xx-x*regress(xx,x);
    ex=e-xx*regress(e,xx);
    sn(r)=det(ex'*ex);
    r=r+1;
end;
[temp,r]=min(sn);
smin=sn(r);
qhat=qs(r);
d=(q<=qhat);
x1=x.*(d*ones(1,length(x(1,:))));
x2=x.*((1-d)*ones(1,length(x(1,:))));
beta1=regress(y,x1);
beta2=regress(y,x2);
yhat=x1*beta1+x2*beta2;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% JOINT_THRESH_CI

% Estimates the threshold in a multivariate threshold model 
% and computes asymptotic confidence intervals

% Format
% [yhat,qhat,qcf_0,qcf_h1,qcf_h2] = joint_thresh_ci(y,x,q,_conf,_graph);

% Inputs
% y	nxm	dependent variable(s)
% x	nxk	independent variables (should include constant)
% q	nx1	threshold variable
% conf_	1x1	level for confidence interval, e.g. conf_=.9
% graph	1x1	Set _graph=1 to view graph of likelihood ratio
%		Set graph_=0 to not display graph

% Outputs
% yhat	nxm	Predicted values for y
% qhat	1x1	Threshold Estimate 
% qcf_0	1x2	Confidence interval for threshold, no heteroskedasticity correction
% qcf_h1	1x2	Confidence interval for threshold, heteroskedasticity correction 
% 		using quadratic variance estimate 
% 		(only if m=1)
% qcf_h2	1x2	Confidence interval for threshold, heteroskedasticity correction 
% 		using variance estimated by Epanechnikov kernel with automatic bandwidth
% 		 (only if m=1)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [yhat,qhat,qcf_h0,qcf_h1,qcf_h2]=joint_thresh_ci(y,x,q,conf_,graph_);
n=length(y(:,1));
k=length(x(1,:));
e=y-x*regress(y,x);
s0=det(e'*e);
n1=round(.05*n)+k;
n2=round(.95*n)-k;
qs=sortrows(q,1);
qs=qs(n1:n2);
qs=unique(qs);
qn=length(qs(:,1));
sn=zeros(qn,1);
r=1;
while r<=qn
    d=(q<=qs(r));
    xx=x.*(d*ones(1,length(x(1,:))));
    xx=xx-x*regress(xx,x);
    ex=e-xx*regress(e,xx);
    sn(r)=det(ex'*ex);
    r=r+1;
end;
[temp,r]=min(sn);
smin=sn(r);
qhat=qs(r);
d=(q<=qhat);
x1=x.*(d*ones(1,length(x(1,:))));
x2=x.*((1-d)*ones(1,length(x(1,:))));
beta1=regress(y,x1);
beta2=regress(y,x2);
yhat=x1*beta1+x2*beta2;
e=y-yhat;
lr=n*(sn/smin-1);
sig2=smin/n;

if length(y(1,:))>1
    eta1=1;
    eta2=1;
else
    r1=(x*(beta1-beta2)).^2;
    r2=r1.*(e.^2);
    qx=[q.^0,q.^1,q.^2];
    qh=[qhat.^0,qhat.^1,qhat.^2];
    m1=(r1'/qx')';
    m2=(r2'/qx')';
    g1=qh*m1;
    g2=qh*m2;
    eta1=((g2'/g1')/sig2')';
    sigq=sqrt(mean((q-mean(q)').^2)');
    hband=2.344*sigq/(n^(.2));
    u=(qhat-q)/hband;
    u2=u.^2;
    f=mean((1-u2).*(u2<=1))'*(.75/hband);
    df=-mean(-u.*(u2<=1))'*(1.5/(hband^2));
    eps=r1-qx*m1;
    sige=(eps'*eps)/(n-3);
    hband=sige/(4*f*((m1(3)+(m1(2)+2*m1(3)*qhat)*df/f)^2));
    u2=((qhat-q)/hband).^2;
    kh=((1-u2)*.75/hband).*(u2<=1);
    g1=mean(kh.*r1)';
    g2=mean(kh.*r2)';
    eta2=((g2'/g1')/sig2')';
end;
c1=-2*log(1-sqrt(conf_));
lr0=(lr>=c1);
lr1=(lr>=(c1*eta1));
lr2=(lr>=(c1*eta2));
if max(lr0)==1
    [temp,indtemp1]=min(lr0);
    revlr0=lr0(1);
    for ii=2:length(lr0)
        revlr0=[lr0(ii);revlr0];
    end;
    [temp,indtemp2]=min(revlr0);
    qcf_h0=[qs(indtemp1),qs(qn+1-indtemp2)];
else
    qcf_h0=[qs(1),qs(qn)];
end;
if max(lr1)==1
    [temp,indtemp1]=min(lr0);
    revlr1=lr1(1);
    for ii=2:length(lr1)
        revlr1=[lr1(ii);revlr1];
    end;
    [temp,indtemp2]=min(revlr1);
    qcf_h1=[qs(indtemp1),qs(qn+1-(indtemp2))];
else
    qcf_h1=[qs(1),qs(qn)];
end;
if max(lr2)==1
    [temp,indtemp1]=min(lr2);
    revlr2=lr2(1);
    for ii=2:length(lr2)
        revlr2=[lr2(ii);revlr2];
    end;
    [temp,indtemp2]=min(revlr2);
    qcf_h2=[qs(indtemp1),qs(qn+1-indtemp2)];
else
    qcf_h2=[qs(1),qs(qn)];
end;

if graph_==1;
    figure;
    clr = ones(qn,1)*c1;
    plot(qs,lr,qs,clr,qs,clr*eta1,qs,clr*eta2);
    grid on;
    title('Confidence Interval Construction for Threshold');
    xlabel('Threshold Variable');
    ylabel('Likelihood Ratio Sequence in Gama');
    legend('LR_n(Gama)','90% Critical','Hetero Corrected-1','Hetero Corrected-2');
end;



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% GMM_LINEAR

% Computes the GMM estimator of a linear model

% Format
% [beta,se,jstat] = gmm_linear(y,z,x);

% Inputs
% y	nx1	dependent variable
% z	nxk	rhs variables
% x	nxl	instruments variables (should include constant and exogenous parts of z), l>=k

% Outputs
% beta	kx1	Regression slope estimates
% se	kx1	standard errors
% jstat	1x1	J Statistic
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [beta,se,jstat]=gmm_linear(y,z,x);
pihat=regress(z,x);
xz=x'*z;
xy=x'*y;
beta=((pihat'*xy)'/(pihat'*xz)')';
e=y-z*beta;
xe=x.*(e*ones(1,length(x(1,:))));
g=inv(xe'*xe);
v=inv(xz'*g*xz);
beta=v*(xz'*g*xy);
se=sqrt(diag(v));
m=x'*(y-z*beta);
jstat=m'*g*m;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% REGRESS

% Computes a linear regression. Uses generalized inverse if X'X is singular

% Format
% beta = regress(y,x);

% Inputs
% y	nxm	dependent variable(s)
% x	nxk	independent variables (should include constant)

% Output
% beta	kxm	Regression slope estimates

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function beta=regress(y,x);
warning off;
mw=' ';
beta=(y'/x')';
[mw,idw] = lastwarn;
lastwarn(' ');
warning on;
if (1-(mw==' '))
    beta=pinv(x'*x)*(x'*y);
end;


