---
title: "Factor IV Estimation in Conditional Moment Models with an application to Inflation Dynamics"
author: "Bertille Antoine and Xiaolin Sun"
date: "2024-03-08"
output:
  pdf_document: default
  html_document: default
  word_document: default
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```


```{r}
library(MASS)
library(ivmodel)
library(sandwich)
```

 HAC Standard Errors
## define the functions 

```{r}
beta.smd.ts.het= function (nobs, X, Y, W, autocov){

W = data.frame(W)
  
b = dim(W)[2]
  
k = matrix(1,nrow = nobs,ncol = nobs)
  # Matrix of size n x length(x)
for (i in 1:b) {

  kx1 = sapply(W[,i], function(Xi) exp(-(W[,i] - Xi)^2 /2))
  k = k * kx1
}
 
 

ktil = k - k[1,1] * diag(nrow = nobs)

X = as.matrix(data.frame(X))

A = (1/nobs)*(1/(nobs))*t(X) %*% ktil %*% X
C = (1/nobs)*(1/(nobs))*t(X) %*% ktil %*% Y
beta =solve(A) %*% C

residual = Y -X %*% beta

ncolX = dim(X)[2]

mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
ktilX = ktil %*% X
B = t(( ktilX) * mat1) %*% ktilX

if (autocov==0) {
mat1 = mat1
B = B
  } else {
for (j in 1: autocov) {
 mat1.j = residual[(j+1):nobs] * residual[1:(nobs-j)] %*% matrix(1,1,ncol = ncolX)
 B.j = t(ktilX[(j+1):nobs,] * mat1.j) %*% ktilX[1:(nobs-j),]
 B =  B + (1 - j/(autocov+1)) * (B.j + t(B.j))
 }
}


varcov = solve(t(X)%*% ktil %*%  X)  %*% B %*% solve(t(X)%*% ktil %*%  X) 
var=diag(varcov)
se = sqrt(var)

seMat = matrix(se, dim(X)[2],1)
tstat = beta/seMat
  
output =data.frame(beta, seMat, tstat)

 return (output)
}
```


```{r}
beta.smd.band.ts.het= function (nobs, X, Y, W, c, autocov){

W = data.frame(W)
  
b = dim(W)[2]
  
k = matrix(1,nrow = nobs,ncol = nobs)
  # Matrix of size n x length(x)
for (i in 1:b) {

  kx1 = sapply(W[,i], function(Xi) exp(-(W[,i] - Xi)^2 /2))
  k = k * kx1
}
 
 
if (c == 0) {
ktil = k - k[1,1] * diag(nrow = nobs)
} else {

for (j in 1:c){
ktil = k - k[1,1] * diag(nrow = nobs)
  ktil[(1+j):nobs, 1:(nobs - j)] = ktil[(1+j):nobs, 1:(nobs - j)] - diag(diag(x = ktil[(1+j):nobs, 1:(nobs - j)]), nrow = (nobs - j))
}
}
ktil[upper.tri(ktil)] = t(ktil)[upper.tri(ktil)]

X = as.matrix(data.frame(X))

A = (1/nobs)*(1/(nobs))*t(X) %*% ktil %*% X
C = (1/nobs)*(1/(nobs))*t(X) %*% ktil %*% Y
beta =solve(A) %*% C

residual = Y -X %*% beta

ncolX = dim(X)[2]

mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
ktilX = ktil %*% X
B = t(( ktilX) * mat1) %*% ktilX

if (autocov==0) {
mat1 = mat1
B = B
  } else {
for (j in 1: autocov) {
 mat1.j = residual[(j+1):nobs] * residual[1:(nobs-j)] %*% matrix(1,1,ncol = ncolX)
 B.j = t(ktilX[(j+1):nobs,] * mat1.j) %*% ktilX[1:(nobs-j),]
 B =  B + (1 - j/(autocov+1)) * (B.j + t(B.j))
 }
}

varcov = solve(t(X)%*% ktil %*%  X)  %*% B %*% solve(t(X)%*% ktil %*%  X) 
var=diag(varcov)
se = sqrt(var)

seMat = matrix(se, dim(X)[2],1)
tstat = beta/seMat
  
output =data.frame(beta, seMat, tstat)

 return (output)
}
```


```{r}
beta.gmm.ts.eff.het= function (nobs, X, Z, Y, W, withZ, autocov){

 c= matrix(1,nobs,1)
  if (withZ==1) {
 Xmat = as.matrix(data.frame(c,X,Z))
 Zmat = as.matrix(data.frame(c,W,Z))
 } else {
 Xmat = as.matrix(data.frame(c,X))
 Zmat = as.matrix(data.frame(c,W))
 }
 
 
 proj = Zmat %*% solve(t(Zmat)%*% Zmat)  %*% t(Zmat)
 beta = solve(t(Xmat)%*% proj %*%  Xmat) %*% (t(Xmat)%*% proj %*% Y)
 residual = Y - Xmat %*% beta
 ncolX = dim(Zmat)[2] 
 mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
 A = t(Zmat * mat1) %*% Zmat
 
 beta.eff = solve(t(Xmat)%*% Zmat %*% solve(A)  %*% t(Zmat) %*%  Xmat) %*% (t(Xmat)%*% Zmat %*% solve(A) %*% t(Zmat) %*% Y)
 
residual = Y - Xmat %*% beta.eff
mat2 = (residual)^2 %*% matrix(1,1,ncol = ncolX)
A = t(Zmat * mat2) %*% Zmat
 
  if (autocov==0) {
mat2 = mat2
A = A
  } else {
 for (j in 1: autocov) {
 mat2.j = residual[(j+1):nobs] * residual[1:(nobs-j)] %*% matrix(1,1,ncol = ncolX)
 A.j = t(Zmat[(j+1):nobs,] * mat2.j) %*% Zmat[1:(nobs-j),]
 A =  A +  (1 - j/(autocov+1)) * (A.j+ t(A.j))
 }
}


 varcov = solve(t(Xmat)%*% Zmat %*% solve(A)  %*% t(Zmat) %*%  Xmat) 

 var=diag(varcov) #extract the diagonal
 se = sqrt(var)


 seMat = matrix(se, dim(Xmat)[2],1)
 tstat = beta/seMat
  
 output =data.frame(beta, seMat, tstat)
 
 return (output)
}
 
```


```{r}
gmm.jtest = function(beta, nobs, X, Z, Y, W, withZ){
  
  c= matrix(1,nobs,1)
  if (withZ==1) {
 Xmat = as.matrix(data.frame(c,X,Z))
 Zmat = as.matrix(data.frame(c,W,Z))
 } else {
 Xmat = as.matrix(data.frame(c,X))
 Zmat = as.matrix(data.frame(c,W))
 }

  beta.eff = beta
  ncolX = dim(Zmat)[2]
  residual = Y - Xmat %*% beta.eff
  mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
  A = t(Zmat * mat1) %*% Zmat
  
  Amat = t(Y - Xmat %*% beta.eff) %*% Zmat
  
  Jstat = Amat %*% solve(A) %*% t(Amat)
  return(Jstat)
}
```

```{r}
gmm.jtest.noconstant = function(beta, nobs, X, Z, Y, W, withZ){
  
  c= matrix(1,nobs,1)
  if (withZ==1) {
 Xmat = as.matrix(data.frame(X,Z))
 Zmat = as.matrix(data.frame(W,Z))
 } else {
 Xmat = as.matrix(data.frame(X))
 Zmat = as.matrix(data.frame(W))
 }

  beta.eff = beta
  ncolX = dim(Zmat)[2]
  residual = Y - Xmat %*% beta.eff
  mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
  A = t(Zmat * mat1) %*% Zmat
  
  Amat = t(Y - Xmat %*% beta.eff) %*% Zmat
  
  Jstat = Amat %*% solve(A) %*% t(Amat)
  return(Jstat)
}
```

```{r}
beta.Bgmm.eff.ts.het= function (nobs, X, Z, Y, W, withZ, Trf, autocov){
 Trf = round(Trf, digits = 0)  
b = dim(W)[2]

 
c_1 = Trf-1
c1 = matrix(1, nrow = c_1, ncol = 1)
 if (withZ==1) {
 Zmat1 = as.matrix(data.frame(c1,W[1:c_1,-b],Z[1:c_1,]))
} else {
 Zmat1 = as.matrix(data.frame(c1,W[1:c_1,-b]))
}

 c_2 = nobs-Trf+1
 c2 = matrix(1, nrow = c_2, ncol = 1)
 if (withZ==1) {
 Zmat2 = as.matrix(data.frame(c2,W[Trf:nobs, -b],Z[Trf:nobs, ]))
} else {
 Zmat2 = as.matrix(data.frame(c2,W[Trf:nobs, -b]))
}
 
 b = dim(Zmat1)[2]
 zeromat1 = matrix(0, nrow = c_1, ncol = b)

 zeromat2 = matrix(0, nrow = c_2, ncol = b)
 
 Zmat1 = cbind(Zmat1,zeromat1)
 Zmat2 = cbind(zeromat2,Zmat2)
 Zmat = rbind(Zmat1, Zmat2)
 
 
 c= matrix(1,nobs,1)
  if (withZ==1) {
 Xmat = as.matrix(data.frame(c,X,Z))
 } else {
 Xmat = as.matrix(data.frame(c,X))
 }
 
 proj = Zmat %*% solve(t(Zmat)%*% Zmat)  %*% t(Zmat) # it can be changed into proj = Zmat %*% t(Zmat)
 beta = solve(t(Xmat)%*% proj %*%  Xmat) %*% (t(Xmat)%*% proj %*% Y)
 residual = Y - Xmat %*% beta
 ncolX = dim(Zmat)[2] 
 mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
 A = t(Zmat * mat1) %*% Zmat
 
 beta.eff = solve(t(Xmat)%*% Zmat %*% solve(A)  %*% t(Zmat) %*%  Xmat) %*% (t(Xmat)%*% Zmat %*% solve(A) %*% t(Zmat) %*% Y)
 
residual = Y - Xmat %*% beta.eff
mat2 = (residual)^2 %*% matrix(1,1,ncol = ncolX)
A = t(Zmat * mat2) %*% Zmat
 
  if (autocov==0) {
mat2 = mat2
A = A
  } else {
 for (j in 1: autocov) {
 mat2.j = residual[(j+1):nobs] * residual[1:(nobs-j)] %*% matrix(1,1,ncol = ncolX)
 A.j = t(Zmat[(j+1):nobs,] * mat2.j) %*% Zmat[1:(nobs-j),]
 A =  A +  (1 - j/(autocov+1)) * (A.j+ t(A.j))
 }
}


 varcov = solve(t(Xmat)%*% Zmat %*% solve(A)  %*% t(Zmat) %*%  Xmat) 

 var=diag(varcov) #extract the diagonal
 se = sqrt(var)


 seMat = matrix(se, dim(Xmat)[2],1)
 tstat = beta/seMat
  
 output =data.frame(beta, seMat, tstat)
 
 return (output)
}
```
 

```{r}
beta.2sls.ts.het= function (nobs, X, Z, Y, W, withZ, autocov){
  
 c= matrix(1,nobs,1)
 if (withZ==1) {
 Xmat = as.matrix(data.frame(c,X,Z))
 Zmat = as.matrix(data.frame(c,W,Z))
 } else {
 Xmat = as.matrix(data.frame(c,X))
 Zmat = as.matrix(data.frame(c,W))
 }
 
 proj = Zmat %*% solve(t(Zmat)%*% Zmat)  %*% t(Zmat)
 beta = solve(t(Xmat)%*% proj %*%  Xmat) %*% (t(Xmat)%*% proj %*% Y)
 residual = Y - Xmat %*% beta
 
ncolX = dim(Zmat)[2]
sigma = mean(residual^2)

mat1 = residual^2 %*% matrix(1,1,ncol = ncolX)
A = t(Zmat * mat1) %*% Zmat

if (autocov==0) {
mat1 = mat1
A = A
  } else {
 for (j in 1: autocov) {
 mat1.j = residual[(j+1):nobs] * residual[1:(nobs-j)] %*% matrix(1,1,ncol = ncolX)
 A.j = t(Zmat[(j+1):nobs,] * mat1.j) %*% Zmat[1:(nobs-j),]
 A =  A +  (1 - j/(autocov+1)) * (A.j+ t(A.j))
 }
}

varcov = solve(t(Xmat) %*% proj %*%  Xmat) %*% t(Xmat) %*% Zmat %*% solve(t(Zmat) %*% Zmat)  %*% A %*% solve(t(Zmat) %*% Zmat)  %*% t(Zmat)  %*%  Xmat %*% solve(t(Xmat) %*% proj %*%  Xmat) 
 


var=diag(varcov) #extract the diagonal
se = sqrt(var)

seMat = matrix(se, dim(Xmat)[2],1)
tstat = beta/seMat
  
output =data.frame(beta, seMat, tstat)
 
 return (output)
}
```



## example



```{r}

mu_2 = c(0,0) 



beta = 0


cov_uv = 0.6
sigma2 = matrix(c(1,cov_uv,cov_uv, 1),2,2)
sigma2

n_ins = 50 
n_loadings = n_ins*2
set.seed(1)
a = rnorm(n_loadings, 1,1)
set.seed(NULL)
mu = matrix(a, nrow = n_ins, ncol = 2)
mu_3 = rep(0, n_ins)
sigma3 = diag(n_ins)

nobsc = c(200, 2000, 200, 2000)
repe = 5000
probz2 = c(0.2, 0.2, 0.05, 0.05)



m=3


nobs = nobsc[m]
lambda = probz2[m]
T_break = (1- lambda)*nobs+1
set.seed(2024)




vandu = mvrnorm(nobs,mu_2,sigma2)

F1 =  runif(nobs,min = -2, max = 2)


F2 = matrix(data=0,nrow = nobs,ncol = 1)
F2[T_break: nobs,1] = 1

Factor = as.matrix(data.frame(F1,F2))
error = mvrnorm(nobs,mu_3,sigma3)

Instruments = Factor %*% t(mu) + error

Y = 10 *(2*F2-1)* (F1 - 2*(F1^3)/5) + vandu[,1]

sig1 = matrix(NA, nobs, 1)
sig1[1] = abs(rnorm(1, mean = 0, sd = 1))
 for (l in 2:nobs) {
  sig1[l] = sqrt(0.1+ 0.6* (sig1[l-1]^2) * (vandu[l-1,2]^2) + 0.3 * (sig1[l-1]^2))
 }


y = Y * beta + vandu[,2]* sig1 

Xvar = Y

pr.ins= prcomp(Instruments,scale = T)

pc1 = pr.ins$x[,1]
pc2 = pr.ins$x[,2]
pc3 = pr.ins$x[,3]

W = as.matrix(data.frame(pc1,pc2,pc3))



 #nobs: number of observations
  #X: the endogenous variable. Xvar is a variable or a vector of variables
  #Y: outcome. y
  #W: the estimated factors.
  #c: the width of the band that eliminates pairs of observations (say s and t) that are not only equal to each other, but also too close to each other. Defined in Equation (30) in the Supplementary Appendix
  #autocov: the truncation parameter in HAC Standard Errors to be chosen. A rule of thumb for choosing m is m = ceiling(0.75*nobs^(1/3))-1. 

m = ceiling(0.75*nobs^(1/3))-1
c = matrix(1,nrow = nobs,ncol = 1)
#### HAC Standard Errors for all estimators
beta.smd.ts.het(nobs,X=Xvar,Y=y,W=W[,1],autocov = m) #FSMD with HAC Standard Errors
beta.smd.ts.het(nobs,X=as.matrix(data.frame(c,Xvar)),Y=y,W=W[,1],autocov = m)
beta.smd.band.ts.het(nobs, X=Xvar,Y=y,W=W[,1],c=1, autocov = m)
beta.smd.band.ts.het(nobs, X = as.matrix(data.frame(c,Xvar)), Y = y, W=W[,1], c=1, autocov = m) 

beta.gmm.ts.eff.het(nobs, X = Xvar, Z=Xvar, Y = y, W=W[,1], withZ=0,autocov = m)#GMM with HAC Standard Errors
beta.2sls.ts.het(nobs, X = Xvar, Z=Xvar, Y = y, W=W[,1], withZ=0,autocov = m)

beta.smd.ts.het(nobs,X=Xvar,Y=y,W=W[,1:2],autocov = 1) #FSMD with HAC Standard Errors
beta.smd.ts.het(nobs,X=as.matrix(data.frame(c,Xvar)),Y=y,W=W[,1:2],autocov = m)
beta.smd.band.ts.het(nobs, X=Xvar,Y=y,W=W[,1:2],c=1, autocov = m)
beta.smd.band.ts.het(nobs, X = as.matrix(data.frame(c,Xvar)), Y = y, W=W[,1:2], c=1, autocov = m) 

beta.gmm.ts.eff.het(nobs, X = Xvar, Z=Xvar, Y = y, W=W[,1:2], withZ=0,autocov = m)#GMM with HAC Standard Errors
beta.2sls.ts.het(nobs, X = Xvar, Z=Xvar, Y = y, W=W[,1:2], withZ=0,autocov = m)

beta.smd.ts.het(nobs,X=Xvar,Y=y,W=W,autocov = 1) #FSMD with HAC Standard Errors
beta.smd.ts.het(nobs,X=as.matrix(data.frame(c,Xvar)),Y=y,W=W,autocov = m)
beta.smd.band.ts.het(nobs, X=Xvar,Y=y,W=W,c=1, autocov = m)
beta.smd.band.ts.het(nobs, X = as.matrix(data.frame(c,Xvar)), Y = y, W=W, c=1, autocov = m) 


beta.gmm.ts.eff.het(nobs, X = Xvar, Z=Xvar, Y = y, W=W, withZ=0,autocov = m)#GMM with HAC Standard Errors
beta.2sls.ts.het(nobs, X = Xvar, Z=Xvar, Y = y, W=W, withZ=0,autocov = m)

```




