Nothing
#############################################################################
#
# Copyright (C) 2021-2031 Bank of Italy
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
#
# @description: BIMETS - Modeling FUNs
#
# @authors: ANDREA LUCIANI
#
# @copyright: Bank of Italy
#
# @license: GPL-3 - GNU GENERAL PUBLIC LICENSE - Version 3
#
#############################################################################
# internal core funs -----------------------------------------------------------
#add an integer to var index: varName[i,] -> varName[i+valueToAdd[j],]
#for each j in valueToAdd
.addToIndexInString <- function (inputS='',valueToAdd=0,transformLeads=FALSE,baseValue=0)
{
#init tmp vars
openIdxs=c()
closeIdxs=c()
flagInsideSquared=FALSE
#cycle in chars and get positions of squared [ and ]
for (idxS in 1:nchar(inputS))
{
#get current char
tmpChar=substr(inputS,idxS,idxS)
if (tmpChar=='[')
{
openIdxs=c(openIdxs,idxS)
flagInsideSquared=TRUE
}
if (tmpChar==']')
{
flagInsideSquared=FALSE
}
if (flagInsideSquared && tmpChar==',')
{
closeIdxs=c(closeIdxs,idxS)
}
}
if (length(openIdxs)==0) return(inputS)
tmpP=1
length_value=length(valueToAdd)
outS=vector('character',length_value)
tryCatch(
{
#cycle every index []
for (idxI in 1:length(openIdxs))
{
#get index str
tmpS=substr(inputS,openIdxs[idxI]+1,closeIdxs[idxI]-1)
#get index as integer
currentI_base=as.integer(tmpS)
if (! is.finite(currentI_base)) stop()
tempSubString=substr(inputS,tmpP,openIdxs[idxI]-1)
#add value to current index
for (idxV in 1:length_value)
{
currentI=currentI_base+valueToAdd[idxV]
#replace index in string
if (transformLeads && currentI>baseValue)
{
outS[idxV]=paste0(outS[idxV]
,tempSubString
,paste0('__LEAD__',currentI-baseValue,'[',baseValue)
)
} else {
outS[idxV]=paste0(outS[idxV]
,tempSubString
,paste0('[',currentI)
)
}
}
tmpP=closeIdxs[idxI]
}
},
error=function(e)
{stop(paste0('.addToIndexInString(): cannot evaluate index "',tmpS,'" ',e$message))}
)
#...create last output
for (idxV in 1:length_value)
outS[idxV]=paste0(outS[idxV]
,substr(inputS,tmpP,nchar(inputS)))
return(outS)
}
#add _ADDFACTOR to a list of var names, e.g. myVAR -> myVAR_ADDFACTOR
.appendAFtoEndVars <- function (inputS='',vName=c(),AF='__ADDFACTOR',...)
{
#replace varName with varName_ADDFACTOR, if varName is not a fun call
#\\b is required to match whole word, e.g. abc != abc_def
for (idxV in 1:length(vName))
inputS=gsub(paste0('\\b(',
vName[idxV],
')\\b($|[^\\(])'),
paste0('\\1\\',AF,'\\2'),
inputS)
return(inputS)
}
#add indexes to a list of var names, e.g. myVAR -> myVAR[indexN,]
.appendIndexToVars <- function (inputS='',vName=c(),indexN='',...)
{
#replace varName with varName[indexN,], if varName is not a fun call
for (idxV in 1:length(vName))
inputS=gsub(paste0('\\b(',
vName[idxV],
')\\b($|[^\\(])'),
paste0('\\1\\[',indexN,',\\]\\2'),
inputS)
return(inputS)
}
#used in PDL
.bm_tartaglia_pdl <- function(degree=1)
{
if (degree==0)
{
return(c(1,-1))
} else
{
levelUpResult=.bm_tartaglia_pdl(degree-1)
outF=levelUpResult[1]
for (idx in 1:(length(levelUpResult)-1))
{
outF=c(outF,abs(levelUpResult[idx])+abs(levelUpResult[idx+1]))
}
outF=c(outF,1)
for (idx in 1:length(outF))
{
if (idx %% 2 ==0) outF[idx]=-outF[idx]
}
return(outF)
}
}
#build reordering blocks from the output of the
#Tarjan #strongly connected components algo
.buildBlocks <- function(incidence_matrix)
{
localT=.TarjanBlocksExtraction(incidence_matrix)
rownames=rownames(incidence_matrix)
vpre=c()
vblocks=list()
#strongly connected nodes are inverse ordered
#in localT
for (idx in length(localT$lists):1)
{
#if single connected component put in vpre
#else we are in a simultaneous group
if (length(localT$lists[[idx]])==1)
{
vpre=c(vpre,localT$lists[[idx]])
} else break
}
#if not in a acyclic graph
if (!(length(vpre)>0 && idx==1 && length(localT$lists[[1]])==1) )
{
idxBlock=0
for (idx2 in idx:1)
{
#new simultaneous group for a new block
if (length(localT$lists[[idx2]])>1)
{
idxBlock=idxBlock+1
vblocks[[idxBlock]]=list()
vblocks[[idxBlock]]$vsim=localT$lists[[idx2]]
vblocks[[idxBlock]]$vpost=c()
} else
{
#add to vpost for current block
vblocks[[idxBlock]]$vpost=c(vblocks[[idxBlock]]$vpost,localT$lists[[idx2]])
}
}
}
if (length(vblocks)>0)
for (idxB in 1:length(vblocks))
{
#convert indexes to var names
if (length(vblocks[[idxB]]$vpost)>0)
vblocks[[idxB]]$vpost=rownames[vblocks[[idxB]]$vpost]
#split vsim vs vfeed in current block using related zone in incidence matrix
tempList=.reorderEquations(incidence_matrix[vblocks[[idxB]]$vsim,vblocks[[idxB]]$vsim] )
#export
vblocks[[idxB]]$vsim=tempList$vsim
vblocks[[idxB]]$vfeed=tempList$vfeed
}
#convert indexes to name
if (length(vpre)>0) vpre=rownames[vpre]
return(list(vpre=vpre,vblocks=vblocks))
}
#check text is single parsable expression
.checkExpression <- function(inputS)
{
if (is.null(inputS)) return(FALSE)
if (length(inputS)!=1) return(FALSE)
if (! is.character(inputS)) return(FALSE)
if (nchar(inputS)==0) return(FALSE)
flagX=TRUE
tryCatch({parse(text=inputS);flagX=FALSE;},error=function(e){})
if (flagX) return(FALSE)
return(TRUE)
}
#chech regressor in behavioral eq
#must not contain operators outside parenthesis
.checkExpressionIsAtomic <- function(inputS=NULL,...)
{
if (is.null(inputS)) return(FALSE)
if (length(inputS)!=1) return(FALSE)
if (! is.character(inputS)) return(FALSE)
if (nchar(inputS)==0) return(FALSE)
#operators to be checked for atomicity
dualOperators=c('\\+','\\-','<','>','<=','>=','!=','==','&','&&','\\|','\\|\\|')
DOcollapse=paste0('(',paste(dualOperators,collapse = '|'),')')
#check operator not in start position
if (grepl(paste0('^',DOcollapse),inputS)) return(FALSE)
#check operator not in end position
if (grepl(paste0(DOcollapse,'$'),inputS)) return(FALSE)
#check parentheses
inputSnc=nchar(inputS)
parCountArray=rep(0,inputSnc)
#each "(" is +1 each ")" is -1
tmpCounter=0
for (idx in 1:inputSnc)
{
actualChar=substring(inputS,idx,idx)
if (actualChar=="(") tmpCounter=tmpCounter+1
if (actualChar==")") tmpCounter=tmpCounter-1
parCountArray[idx]=tmpCounter
}
#get position of operators
DOpos=as.numeric(gregexpr(DOcollapse,inputS)[[1]])
#operators cannot be out of parentheses
if (any(DOpos>0) && any(parCountArray[DOpos]==0)) return(FALSE)
#check expression
if (! .checkExpression(inputS)) return(FALSE)
return(TRUE)
}
#check bimets version a model has been built with
#if different from current bimets version issues a warning
.checkModelBimetsVersion <- function(model,callerName='.checkModelBimetsVersion')
{
if (is.null(model$bimets_version)) # || model$bimets_version != getOption('BIMETS_VERSION'))
warning(paste0(callerName,'(): warning, current model "',model$modelName,'" has been built with an outdated BIMETS version. Please recreate the model via the LOAD_MODEL() function.\n'))
return(NULL)
}
#combine list by names
.combineList <- function(list1=NULL,list2=NULL)
{
if (is.null(list1)) return(list2)
if ((!is.list(list1)) || (!is.list(list2))) stop('.combineList(): inputs must be of class list().')
outList=list1
matchedNames=match(names(list2), names(list1))
commonIndexes=which(!is.na(matchedNames))
if (length(commonIndexes) > 0)
{
#give priority to list2 in matched names
matchedNames=matchedNames[!is.na(matchedNames)]
outList[matchedNames] = list2[commonIndexes]
#append elements of 'list2' with unmatched names
outList=c(outList, list2[-commonIndexes])
}
else
{
outList=c(outList, list2)
}
return(outList)
}
#move vars from local env localE into global, useful in debugging
.copyLocalEnvInToGlobal <- function(sourceE=NULL,destE=.GlobalEnv,...)
{
if (is.null(sourceE))
{
cat('Please provide a valid environment.\n')
} else {
lapply(names(sourceE),function(n){assign(n,get(n,envir=sourceE),envir=destE) })
}
}
#return arguments as text (2 or more) and comma positions for the first
#occurrence of function fName in string inputS
.explodeFunctionCall <- function (inputS='',fName='',...)
{
outL=list()
#check fun name exists in string
if (substr(fName,1,1)=='.')
{
fNameEx=paste0('\\.\\b(',gsub("\\.","",fName),')\\b\\(')
} else {
#must move dot out of \\b
fNameEx=paste0('\\b(',fName,')\\b\\(')
}
#check function call exists in string
#regexpr returns only first occurrence
firstLoc=regexpr(fNameEx,inputS)
#if none then exit
if (firstLoc==-1) return(outL)
#remove attributes from regex results
attributes(firstLoc)=NULL
#init tmp vars... consider we start whit one "("
openP=1 #for round ()
openSP=0 #for squared []
#outputs
commaPos=c()
args=c()
argsStart=firstLoc+nchar(fName)+1
argsEnd=c()
#cycle in chars
for (idxS in (argsStart):nchar(inputS))
{
#get char
tmpChar=substr(inputS,idxS,idxS)
if (tmpChar=='(')
{
openP=openP+1
} else if (tmpChar==')')
{
openP=openP-1
if (openP==0 && openSP==0)
{
#we are exiting function call
argsEnd=idxS-1
break
}
} else if (tmpChar==',' && openP==1 && openSP==0)
{
#we are in comma position separating fName arguments
commaPos=c(commaPos,idxS)
} else if (tmpChar=='[')
{
#we need to account also squared []
openSP=openSP+1
} else if (tmpChar==']')
{
openSP=openSP-1
}
}
#get arguments
argsCount=length(commaPos)+1
if (argsCount==1)
{
args=substr(inputS,argsStart,argsEnd)
} else
for (idxA in 1:argsCount)
{
#first argument
if (idxA==1)
{
args=c(args,substr(inputS,argsStart,commaPos[idxA]-1))
} else if (argsCount==idxA)
{
#last argument
args=c(args,substr(inputS,commaPos[idxA-1]+1,argsEnd))
} else
{
args=c(args,substr(inputS,commaPos[idxA-1]+1,commaPos[idxA]-1))
}
}
#trim spaces
args=gsub("\\s*", "", args)
#results
outL$firstLoc=firstLoc
outL$commaPos=commaPos
outL$argsStart=argsStart
outL$argsEnd=argsEnd
outL$argsCount=argsCount
outL$args=args
return(outL)
}
#transform first MAVE in inputS into exploded expression with related lags
.explodeSingleMAVE <- function (inputS='',...)
{
#init tmp var
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_MAVE')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLag=0
#if not specified tslag=1
if (outSE$argsCount==1)
{
tsLag=1
} else
{
tryCatch({
tsLag=as.integer(outSE$args[2])
if (! ( is.finite(tsLag) && tsLag %%1 ==0 && tsLag>0)) stop()
},error=function(e){stop(paste0('.explodeSingleMAVE(): window size must be a positive integer. ',e$message))}
)
}
outTS=outSE$args[1]
tempArg=outTS
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
#MAVE(varName[a,],b) -> (0+varName[a,]+varName[a-1,]+...+varName[a-b,])/b
if (tsLag>1)
{
outADTS=.addToIndexInString(tempArg,1-2:tsLag)
for (idxMA in 1:length(outADTS))
outTS=paste0(outTS,'+',outADTS[idxMA])
}
ncIS=nchar(inputS)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
outL$output=paste0(header
,'((',
outTS,
')/',tsLag,')',
trailer)
#store flag if mod has been made
outL$flag=TRUE
#outL$tsLag=tsLag
return(outL)
}
#explode all MAVE()
.explodeMAVE <- function (inputS='',...)
{
tryCatch({
tmpL=.explodeSingleMAVE(inputS)
#while we have more MAVE()
while(tmpL$flag)
{
tmpL=.explodeSingleMAVE(tmpL$output)
}
},error=function(e){stop(paste0('.explodeMAVE(): ',e$message))})
return(tmpL)
}
#transform first MTOT in inputS into exploded expression with related lags
.explodeSingleMTOT <- function (inputS='',...)
{
#init tmp var
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_MTOT')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLag=0
#if not specified tslag=1
if (outSE$argsCount==1)
{
tsLag=1
} else
{
tryCatch({
tsLag=as.integer(outSE$args[2])
if (! ( is.finite(tsLag) && tsLag %%1 ==0 && tsLag>0)) stop()
},error=function(e){stop(paste0('.explodeSingleMTOT(): window size must be a positive integer. ',e$message))}
)
}
outTS=outSE$args[1]
tempArg=outTS
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
#MTOT(varName[a,],b) -> 0+varName[a,]+varName[a-1,]+...+varName[a-b,]
if (tsLag>1)
{
outADTS=.addToIndexInString(tempArg,1-2:tsLag)
for (idxMA in 1:length(outADTS))
outTS=paste0(outTS,'+',outADTS[idxMA])
}
ncIS=nchar(inputS)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
outL$output=paste0(header
,'((',
outTS,
'))',
trailer)
#store flag if mod has been made
outL$flag=TRUE
#outL$tsLag=tsLag
return(outL)
}
#explode all MTOT()
.explodeMTOT <- function (inputS='',...)
{
tryCatch({
tmpL=.explodeSingleMTOT(inputS)
#while we have more MTOT()
while(tmpL$flag)
{
tmpL=.explodeSingleMTOT(tmpL$output)
}
},error=function(e){stop(paste0('.explodeMTOT(): ',e$message))})
return(tmpL)
}
#transform first TSLAG in inputS into exploded expression with related lags
.explodeSingleTSLAG <- function (inputS='',...)
{
#init tmp vars
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_TSLAG')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLag=0
#no lag provided so it is 1
if (outSE$argsCount==1)
{
tsLag=1
} else
{ #otherwise eval
tryCatch({
tsLag=as.integer(outSE$args[2])
if (! ( is.finite(tsLag) && tsLag %%1 ==0 && tsLag>=0)) stop()
},error=function(e){stop(paste0('.explodeSingleTSLAG(): lag value must be a non-negative integer. ',e$message))}
)
}
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
#replace varName[a,] -> varName[a-lag,]
ncIS=nchar(inputS)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
outL$output=paste0(header
,'(',
.addToIndexInString(outSE$args[1],-tsLag),
')',
trailer)
#store flag if mod has been made
outL$flag=TRUE
return(outL)
}
#explode all TSLAG()
.explodeTSLAG <- function (inputS='',...)
{
tryCatch({
#explode first TSLAG
tmpL=.explodeSingleTSLAG(inputS)
#while exist a TSLAG()...
while(tmpL$flag)
{
tmpL=.explodeSingleTSLAG(tmpL$output)
}
},error=function(e){stop(paste0('.explodeTSLAG(): ',e$message))})
return(tmpL)
}
#transform first TSLEAD in inputS into exploded expression with related lags
.explodeSingleTSLEAD <- function (inputS='',...)
{
#init tmp vars
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_TSLEAD')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLead=0
#no lag provided so it is 1
if (outSE$argsCount==1)
{
tsLead=1
} else
{ #otherwise eval
tryCatch({
tsLead=as.integer(outSE$args[2])
if (! ( is.finite(tsLead) && tsLead %%1 ==0 && tsLead>=0)) stop()
},error=function(e){stop(paste0('.explodeSingleTSLEAD(): lead value must be a non-negative integer. ',e$message))}
)
}
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
#replace varName[a,] -> varName[a-lag,]
ncIS=nchar(inputS)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
outL$output=paste0(header
,'(',
.addToIndexInString(outSE$args[1],tsLead),
')',
trailer)
#store flag if mod has been made
outL$flag=TRUE
return(outL)
}
#explode all TSLEAD()
.explodeTSLEAD <- function (inputS='',...)
{
tryCatch({
#explode first TSLEAD
tmpL=.explodeSingleTSLEAD(inputS)
#while exist a TSLEAD()...
while(tmpL$flag)
{
tmpL=.explodeSingleTSLEAD(tmpL$output)
}
},error=function(e){stop(paste0('.explodeTSLEAD(): ',e$message))})
return(tmpL)
}
#transform first DELTA in inputS into exploded expression with related lags
.explodeSingleTSDELTA <- function (inputS='',...)
{
#init tmp var
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_TSDELTA')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLag=0
#if no specified tslag=1
if (outSE$argsCount==1)
{
tsLag=1
} else
{
tryCatch({
tsLag=as.integer(outSE$args[2])
if (! ( is.finite(tsLag) && tsLag %%1 ==0 && tsLag>0)) stop()
},error=function(e){stop(paste0('.explodeSingleTSDELTA(): DELTA value must be a positive integer. ',e$message))}
)
}
tempArg=outSE$args[1]
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
ncIS=nchar(inputS)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
#DELTA(varName[a,],b)=((varName[a,])-(varName[a-b,]))
outL$output=paste0(header
,'((',
tempArg,
')-(',
.addToIndexInString(tempArg,-tsLag),
'))',
trailer)
#store flag if mod has been made
outL$flag=TRUE
return(outL)
}
#explode all DELTA()
.explodeTSDELTA <- function (inputS='',...)
{
tryCatch({
tmpL=.explodeSingleTSDELTA(inputS)
#while we have more DELTA()
while(tmpL$flag)
{
tmpL=.explodeSingleTSDELTA(tmpL$output)
}
},error=function(e){stop(paste0('.explodeTSDELTA(): ',e$message))})
return(tmpL)
}
#transform first DELTALOG in inputS into exploded expression with related lags
.explodeSingleTSDELTALOG <- function (inputS='',...)
{
#init tmp var
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_TSDELTALOG')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLag=0
#if no specified tslag=1
if (outSE$argsCount==1)
{
tsLag=1
} else
{
tryCatch({
tsLag=as.integer(outSE$args[2])
if (! ( is.finite(tsLag) && tsLag %%1 ==0 && tsLag>0)) stop()
},error=function(e){stop(paste0('.explodeSingleTSDELTALOG(): DELTALOG value must be a positive integer. ',e$message))}
)
}
tempArg=outSE$args[1]
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
ncIS=nchar(inputS)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
#DELTALOG(varName[a,],b)=(log((varName[a,])/(varName[a-b,])))
outL$output=paste0(header
,'(log((',
tempArg,
')/(',
.addToIndexInString(tempArg,-tsLag),
')))',
trailer)
#store flag if mod has been made
outL$flag=TRUE
return(outL)
}
#explode all DELTALOG()
.explodeTSDELTALOG <- function (inputS='',...)
{
tryCatch({
tmpL=.explodeSingleTSDELTALOG(inputS)
#while we have more DELTALOG()
while(tmpL$flag)
{
tmpL=.explodeSingleTSDELTALOG(tmpL$output)
}
},error=function(e){stop(paste0('.explodeTSDELTALOG(): ',e$message))})
return(tmpL)
}
#transform first DELTAP in inputS into exploded expression with related lags
.explodeSingleTSDELTAP <- function (inputS='',...)
{
#init tmp var
outL=list()
outL$output=inputS
outL$flag=FALSE
outSE=.explodeFunctionCall(inputS,'.MODEL_TSDELTAP')
#no fun call so exit
if (length(outSE)==0) return(outL)
tsLag=0
#if no specified lag=1
if (outSE$argsCount==1)
{
tsLag=1
} else
{
tryCatch({
tsLag=as.integer(outSE$args[2])
if (! ( is.finite(tsLag) && tsLag %%1 ==0 && tsLag>0)) stop()
},error=function(e){stop(paste0('.explodeSingleTSDELTAP(): DELTAP value must be a positive integer. ',e$message))}
)
}
tempArg=outSE$args[1]
firstLoc=outSE$firstLoc
argsEnd=outSE$argsEnd
ncIS=nchar(inputS)
tempLagged=.addToIndexInString(tempArg,-tsLag)
if (firstLoc>1) header=substr(inputS,1,firstLoc-1)
else header=''
if (argsEnd<ncIS-1) trailer=substr(inputS,argsEnd+2,ncIS)
else trailer=''
#DELTAP(varName[a,],b)=(100*((varName[a,])-(varName[a-b,]))/(varName[a-b,]))
outL$output=paste0(header
,'(100*((',
tempArg,
')-(',
tempLagged,
'))/(',tempLagged,'))',
trailer
)
#store flag if mod has been made
outL$flag=TRUE
return(outL)
}
#explode all DELTAP()
.explodeTSDELTAP <- function (inputS='',...)
{
tryCatch({
tmpL=.explodeSingleTSDELTAP(inputS)
#while we have more DELTAP()
while(tmpL$flag)
{
tmpL=.explodeSingleTSDELTAP(tmpL$output)
}
},error=function(e){stop(paste0('.explodeTSDELTAP(): ',e$message))})
return(tmpL)
}
#extract function names from string
.extractFunsNames <- function(inputS=NULL)
{
if (is.null(inputS)) return(character(0))
out=regmatches(inputS,gregexpr('(\\w+)\\(',inputS))
out=gsub('\\(','',out[[1]])
return(out)
}
#return vName[x,] in inputS that has x==baseIndex
#baseIndex default to 0, i.e. y[0,]=...
.getIncidenceVendogs <- function (currentVendog,inputS='',vName=c(),baseIndex=0,...)
{
if (length(vName)==0) return(NULL)
#remove "currentVendog=[indexN,]" and ".MODEL_VIF(currentVendog[indexN,]"
#\\b is required to match whole word, e.g. abc != abc_def
inputS=gsub(paste0('\\b(',currentVendog,')\\b\\[\\s*',baseIndex,'\\s*,\\s*\\]\\s*\\='),'',inputS)
inputS=gsub(paste0('.MODEL_VIF\\(\\s*',currentVendog,'\\[\\s*',baseIndex,'\\s*,\\s*\\]\\s*\\,'),'\\(',inputS)
trailer=paste0('\\[',baseIndex,',')
outC=regmatches(inputS,gregexpr(paste0('(\\w+)',trailer),inputS))
outC=gsub(trailer,'',outC[[1]])
outC=outC[outC %in% vName]
return(outC)
}
#retrieve minimum lag / maximium lead for all lagged/leaded vars
.getLowerLagAndHigherLead <- function (inputS='',...)
{
outL=+Inf
outH=-Inf
openIdxs=c()
closeIdxs=c()
#cycle in chars and get sbracket positions
for (idxS in 1:nchar(inputS))
{
#get current char
tmpChar=substr(inputS,idxS,idxS)
if (tmpChar=='[')
{
openIdxs=c(openIdxs,idxS)
}
if (tmpChar==']')
{
closeIdxs=c(closeIdxs,idxS)
}
}
if (length(openIdxs) ==0) return(0)
tryCatch(
{
#cycle in indexes
for (idxI in 1:length(openIdxs))
{
#get index as string
tmpS=substr(inputS,openIdxs[idxI]+1,closeIdxs[idxI]-1)
tmpS=strsplit(tmpS,',')[[1]][1]
#get index as numeric
currentI=as.integer(tmpS)
if (! is.finite(currentI)) stop()
#get minimum
outL=min(outL,currentI)
#get maximum
outH=max(outH,currentI)
}},
error=function(e)
{stop(paste0('.getLowerLagAndHigherLead(): cannot evaluate index "',tmpS,'"'))}
)
out=list()
out$outL=outL
out$outH=outH
return(out)
}
#lead a simulation expression eqSimText by 1:(simSteps-1) period starting from base value
#and transform leaded references, e.g. var[i,] -> to var__LEAD__j[0,], i>simSteps, j <- i-simSteps
.leadEqSim <- function(currentVendog,eqSimText,baseValue,simSteps)
{
outSimList=list()
tempATIS=.addToIndexInString(eqSimText,1:(simSteps-1), TRUE, baseValue)
outS=paste0(currentVendog,'__LEAD__')
for (idxSS in 1:length(tempATIS))
{
outSimList[[paste0(outS,idxSS)]]=tempATIS[idxSS]
}
return(outSimList)
}
#convert funs names in model
.MODEL_MOD_FUNC_NAMES <- function(inputS=NULL)
{
inputS=gsub('TSLEAD\\(','LEAD(',inputS,ignore.case=TRUE)
inputS=gsub('LEAD\\(','.MODEL_TSLEAD(',inputS,ignore.case=TRUE)
inputS=gsub('TSLAG\\(','LAG(',inputS,ignore.case=TRUE)
inputS=gsub('LAG\\(','.MODEL_TSLAG(',inputS,ignore.case=TRUE)
inputS=gsub('TSDELTA\\(','.MODEL_TSDELTA(',inputS,ignore.case=TRUE)
inputS=gsub('DEL\\(','.MODEL_TSDELTA(',inputS,ignore.case=TRUE)
inputS=gsub('LOG\\(','log(',inputS,ignore.case=TRUE)
inputS=gsub('EXP\\(','exp(',inputS,ignore.case=TRUE)
inputS=gsub('ABS\\(','abs(',inputS,ignore.case=TRUE)
inputS=gsub('MOVAVG\\(','MAVE(',inputS,ignore.case=TRUE)
inputS=gsub('MAVE\\(','.MODEL_MAVE(',inputS,ignore.case=TRUE)
inputS=gsub('MOVSUM\\(','MTOT(',inputS,ignore.case=TRUE)
inputS=gsub('MTOT\\(','.MODEL_MTOT(',inputS,ignore.case=TRUE)
inputS=gsub('TSDELTAP\\(','.MODEL_TSDELTAP(',inputS,ignore.case=TRUE)
inputS=gsub('TSDELTALOG\\(','.MODEL_TSDELTALOG(',inputS,ignore.case=TRUE)
return(inputS)
}
#wrapper for base::cat
.MODEL_outputText <- function(...,sep=' ',outputText=TRUE)
{
if (outputText) cat(...,sep=sep)
return(NULL)
}
#used in Estimate
.MODEL_MAVE <- function(x=NULL,L=1)
{
return(MAVE(x=x, L=L, avoidCompliance=TRUE))
}
#used in Estimate
.MODEL_MTOT <- function(x=NULL,L=1)
{
return(MTOT(x=x, L=L, avoidCompliance=TRUE))
}
#used in Estimate
.MODEL_TSDELTA <- function(x=NULL,L=1)
{
return(TSDELTA(x=x, L=L, avoidCompliance=TRUE))
}
#used in Estimate
.MODEL_TSDELTALOG <- function(x=NULL,L=1)
{
return(TSDELTALOG(x=x, L=L, avoidCompliance=TRUE))
}
#used in Estimate
.MODEL_TSDELTAP <- function(x=NULL,L=1)
{
return(TSDELTAP(x=x, L=L, avoidCompliance=TRUE))
}
#used in Estimate
.MODEL_TSLAG <- function(ts,lag=1)
{
return(TSLAG(ts, lag, avoidCompliance=TRUE, verbose=FALSE))
}
#used in Estimate
.MODEL_TSLEAD <- function(ts,lead=1)
{
return(TSLEAD(ts, lead, avoidCompliance=TRUE, verbose=FALSE))
}
#evaluate IF> condition in simulation of identities
#e.g. vendog <- 4 if vexog>0 ==> vendog <- MODEL_VIF(vendog,vexog>0,4)
.MODEL_VIF <- function(vendog,index_which=TRUE,values)
{
if (! all(is.finite(index_which))) stop('Uncomputable IF condition.')
#get vendog of identity
tmpV=vendog
#condition can be boolean or array
if (length(index_which)>1)
{
tmpI=which(index_which)
} else {
tmpI=index_which
}
#RHS can be scalar or array
if (length(values)>1)
{
tmpV[tmpI]=values[tmpI]
} else {
tmpV[tmpI]=values
}
return(tmpV)
}
.parseLhsEQ <- function (inputS='',allowedLhsEQfuns=NULL,...)
{
outL=list()
#cycle in available lhs funs
for (funName in allowedLhsEQfuns)
{
#search current fun name in input expression
tmpList=.explodeFunctionCall(inputS,funName)
#we return first match
if (length(tmpList)>0 && tmpList$firstLoc==1)
{
outL=tmpList
outL$funName=funName
outL$raw=inputS
return(outL)
}
}
#no lhs fun found so return identity
outL$funName='I'
outL$args=inputS
outL$raw=inputS
return(outL)
}
#print verbose stuff during simulation
#do not use this fun outside main simulation cycle
.printVerboseSim <- function(phase=NULL,
ConstantAdjustment,
verboseVars,
frequency,
TSRANGE,
simSteps,
simIterLoopIdx,
idxB,
idxIter,
model_max_lag_1,
length_model_vexog,
model_vendog,
model_vexog,
replica,
localE,
model_vpre,
model_vsim,
model_vpost,
hasLeads)
{
verboseVarsAugmented=verboseVars
model_vendog_augmented=model_vendog
model_vexog_augmented=model_vexog
if (hasLeads && simSteps>1)
{
for (idx in 1:(simSteps-1))
{
verboseVarsAugmented=c(verboseVarsAugmented,paste0(verboseVars,'__LEAD__',idx))
model_vexog_augmented=c(model_vexog_augmented,paste0(model_vexog,'__LEAD__',idx))
model_vendog_augmented=c(model_vendog_augmented,paste0(model_vendog,'__LEAD__',idx))
}
}
if (phase=='VPRE')
{
if(length(model_vpre)==0) return()
verboseVarsEndoActive=verboseVarsAugmented[verboseVarsAugmented %in% model_vpre]
} else if (phase=='VSIM')
{
if(length(model_vsim[[idxB]])==0) return()
verboseVarsEndoActive=verboseVarsAugmented[verboseVarsAugmented %in% model_vsim[[idxB]]]
} else if (phase=='VPOST')
{
if(length(model_vpost[[idxB]])==0) return()
verboseVarsEndoActive=verboseVarsAugmented[verboseVarsAugmented %in% model_vpost[[idxB]]]
} else if (phase=='ERROR')
{
verboseVarsEndoActive=verboseVarsAugmented[verboseVarsAugmented %in% model_vendog_augmented]
} else if (phase=='RESCHECK')
{
verboseVarsEndoActive=verboseVarsAugmented[verboseVarsAugmented %in% model_vendog_augmented]
} else return()
verboseVarsExog=verboseVarsAugmented[verboseVarsAugmented %in% model_vexog_augmented]
if (length(verboseVarsEndoActive)==0 && length(verboseVarsExog)==0)
return()
if (phase=='VPRE')
{
model_vars_adj=model_vpre
} else if (phase=='VSIM')
{
model_vars_adj=model_vsim[[idxB]]
} else if (phase=='VPOST')
{
model_vars_adj=model_vpost[[idxB]]
} else if (phase=='ERROR')
{
model_vars_adj=NULL
} else if (phase=='RESCHECK')
{
model_vars_adj=NULL
} else return()
if (hasLeads && simSteps>1 && length(model_vars_adj)>0)
{
for (idx in 1:length(model_vars_adj))
{
tmpSS=strsplit(model_vars_adj[idx],'__LEAD__')[[1]]
tmpLHF=tmpSS[1]
tmpRHS=ifelse(length(tmpSS)>1,as.integer(tmpSS[2]),0)
model_vars_adj[idx]=paste0(tmpLHF,
' (',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+tmpRHS),f=frequency),collapse='-'),
')')
}
}
if (phase=='VPRE')
{
cat('\nVPRE. Vars: ',paste0(model_vars_adj,collapse=', '),'\n')
} else if (phase=='VSIM')
{
cat(paste0('\nVSIM, block ',idxB,', iteration ',idxIter,'. Vars: ',
paste0(model_vars_adj,collapse=', '),'\n'))
} else if (phase=='VPOST')
{
cat(paste0('\nVPOST, block ',idxB,', iteration ',idxIter,'. Vars: ',
paste0(model_vars_adj,collapse=', '),'\n'))
} else if (phase=='ERROR')
{
cat('\nERROR SNAPSHOT:\n')
} else if (phase=='RESCHECK')
{
cat('\nRESCHECK SNAPSHOT:\n')
} else return()
doubleFormat="%20.11g"
simPeriods=1
maxReplicas=3
printedReplicas=min(replica,maxReplicas)
if (length(ConstantAdjustment)>0 )
{
namesCAaugmented=names(ConstantAdjustment)
if (hasLeads && simSteps>1)
for (idx in 1:(simSteps-1))
namesCAaugmented=c(namesCAaugmented,paste0(names(ConstantAdjustment),'__LEAD__',idx))
verboseVarsEndoActiveCA=verboseVarsEndoActive[verboseVarsEndoActive %in% namesCAaugmented]
if (length(verboseVarsEndoActiveCA)>0)
{
cat('\tCONSTANT ADJUSTMENTS:\n')
for (tmpVA in verboseVarsEndoActiveCA)
{
tmpV=tmpVA
tmpSI=0
if (grepl('__LEAD__',tmpVA))
{
tmpSS=strsplit(tmpVA,'__LEAD__')[[1]]
tmpV=tmpSS[1]
tmpSI=as.integer(tmpSS[2])
}
cat(paste0(
'\tPrd. ',
sprintf("%4i",simIterLoopIdx+tmpSI),', ',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx+tmpSI-1),f=frequency),collapse='-'),', ',
'iter. ',
sprintf("%4i",idxIter),' ',
sprintf("%17s CA",tmpV),' ='))
for (idxR in 1:printedReplicas)
cat(sprintf(doubleFormat,localE[[paste0(tmpV,'__ADDFACTOR',ifelse(tmpSI>0,paste0('__LEAD__',tmpSI),''))]][ model_max_lag_1,idxR]))
if (replica>maxReplicas) cat('\t(trunc)')
cat('\n')
}
}
}
if (length(verboseVarsExog)>0)
{
cat('\tVEXOGS:\n')
for (tmpVA in verboseVarsExog)
{
tmpV=tmpVA
tmpSI=0
if (grepl('__LEAD__',tmpVA))
{
tmpSS=strsplit(tmpVA,'__LEAD__')[[1]]
tmpV=tmpSS[1]
tmpSI=as.integer(tmpSS[2])
}
cat(paste0(
'\tPrd. ',
sprintf("%4i",simIterLoopIdx+tmpSI),', ',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx+tmpSI-1),f=frequency),collapse='-'),', ',
'iter. ',
sprintf("%4i",idxIter),' ',
sprintf("%20s",tmpV),' ='))
for (idxR in 1:printedReplicas)
cat(sprintf(doubleFormat,localE[[paste0(tmpV,ifelse(tmpSI>0,paste0('__LEAD__',tmpSI),''))]][ model_max_lag_1,idxR]))
if (replica>maxReplicas) cat('\t(trunc)')
cat('\n')
}
}
if (length(verboseVarsEndoActive)>0)
{
cat('\tVENDOGS:\n')
for (tmpVA in verboseVarsEndoActive)
{
tmpV=tmpVA
tmpSI=0
if (grepl('__LEAD__',tmpVA))
{
tmpSS=strsplit(tmpVA,'__LEAD__')[[1]]
tmpV=tmpSS[1]
tmpSI=as.integer(tmpSS[2])
}
cat(paste0(
'\tPrd. ',
sprintf("%4i",simIterLoopIdx+tmpSI),', ',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx+tmpSI-1),f=frequency),collapse='-'),', ',
'iter. ',
sprintf("%4i",idxIter),' ',
sprintf("%20s",tmpV),' ='))
for (idxR in 1:printedReplicas)
cat(sprintf(doubleFormat,localE[[paste0(tmpV,ifelse(tmpSI>0,paste0('__LEAD__',tmpSI),''))]][ model_max_lag_1,idxR]))
if (replica>maxReplicas) cat('\t(trunc)')
cat('\n')
}
}
}
#export main RexEx definitions
.RegExGlobalDefinition <- function()
{
#symbols/funcs allowed on EQ
reservedKeyw=c('LOG','TSLAG','LAG','TSLEAD','LEAD','MOVAVG','MAVE','EXP','TSDELTA','DEL','ABS','MOVSUM','MTOT','TSDELTAP','TSDELTALOG')
#list of availables lhs funs
allowedLhsEQfuns=c('LOG','EXP','TSDELTA','DEL','TSDELTAP','TSDELTALOG')
allowedLhsEQfunsPub=c('LOG','EXP','TSDELTA','TSDELTAP','TSDELTALOG')
#what to remove from equations in order to obtains symbol names
#symOnEqCleaner='(\\+|\\-|\\(|\\)|\\*|\\/|\\,|\\=|LOG\\(|LAG\\(|MAVE\\(|EXP\\(|DEL\\(|ABS\\()'
symOnEqCleaner=paste0('(\\+|\\-|\\(|\\)|\\*|\\/|\\,|\\^|\\=|<|>|\\.GE\\.|\\.LE\\.|\\.GT\\.|\\.LT\\.|\\.EQ\\.',paste(paste0('|',reservedKeyw,'\\('),collapse=''),')')
symOnIfCleaner=paste0('(\\&|\\||\\+|\\-|\\(|\\)|\\*|\\/|\\,|\\^|\\=|<|>|\\.GE\\.|\\.LE\\.|\\.GT\\.|\\.LT\\.|\\.EQ\\.',paste(paste0('|',reservedKeyw,'\\('),collapse=''),')')
#regex allowed on symbol names
allowedCharOnNameToken='[a-zA-Z_]+[a-zA-Z0-9_]*'
allowedCharOnName=paste0('^',allowedCharOnNameToken,'$')
#regex allowed on numbers (we use only 'strongCharsOnNumbs')
charsOnNumbs='([0-9]+[\\.]?|[\\.]?[0-9]+|[0-9]+\\.[0-9]+|pi)'
charsOnNumWithSign=paste0('(\\+|-)?',charsOnNumbs)
strongCharOnNumbs=paste0('^',charsOnNumbs,'$')
strongCharOnNumbsWithSign=paste0('^',charsOnNumWithSign,'$')
return(list(reservedKeyw=reservedKeyw,
symOnEqCleaner=symOnEqCleaner,
symOnIfCleaner=symOnIfCleaner,
allowedCharOnName=allowedCharOnName,
allowedCharOnNameToken=allowedCharOnNameToken,
charsOnNumbs=charsOnNumbs,
charsOnNumWithSign=charsOnNumWithSign,
strongCharOnNumbs=strongCharOnNumbs,
strongCharOnNumbsWithSign=strongCharOnNumbsWithSign,
allowedLhsEQfuns=allowedLhsEQfuns,
allowedLhsEQfunsPub=allowedLhsEQfunsPub))
}
#reorder equation evaluation sequence based on incidence matrix
.reorderEquations <- function(incidence_matrix)
{
if (is.null(incidence_matrix))
return(list(
vsim=NULL,
vfeed=NULL
))
#we need original incidence_matrix later...
temp_incidence_matrix=incidence_matrix
#get VFEED endogenous
VFEED=c()
if (dim(temp_incidence_matrix)[1]>0) while(1) {
flag=1
while(flag)
{
flag=0
#RULE #2c
temp_vendog=colSums(temp_incidence_matrix)
which_temp_vendog=(temp_vendog==0)
if (any(which_temp_vendog))
{
temp_incidence_matrix=temp_incidence_matrix[! which_temp_vendog,! which_temp_vendog, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
flag=1
}
#RULE #2r
temp_vendog=rowSums(temp_incidence_matrix)
which_temp_vendog=(temp_vendog==0)
if (any(which_temp_vendog))
{
temp_incidence_matrix=temp_incidence_matrix[! which_temp_vendog,! which_temp_vendog, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
flag=1
}
#RULE #3
#if sum column is 1 merge and remove it
temp_vendog=colSums(temp_incidence_matrix)
which_temp_vendog=which(temp_vendog==1)
if (length(which_temp_vendog)>0)
{
for (idx in which_temp_vendog)
{
dest_row=which(temp_incidence_matrix[,idx]==1)
temp_incidence_matrix[dest_row,which(temp_incidence_matrix[idx,]==1)]=1
}
for (idx in which_temp_vendog)
if (T && temp_incidence_matrix[idx,idx]==1 )
{
VFEED=c(VFEED,rownames(temp_incidence_matrix)[idx])
}
temp_incidence_matrix=temp_incidence_matrix[-which_temp_vendog,-which_temp_vendog, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
flag=1
}
#if sum rows is 1 merge and remove it
temp_vendog=rowSums(temp_incidence_matrix)
which_temp_vendog=which(temp_vendog==1)
if (length(which_temp_vendog)>0)
{
for (idx in which_temp_vendog)
{
dest_col=which(temp_incidence_matrix[idx,]==1)
temp_incidence_matrix[which(temp_incidence_matrix[,idx]==1),dest_col]=1
}
for (idx in which_temp_vendog)
if (temp_incidence_matrix[idx,idx]==1 )
{ VFEED=c(VFEED,rownames(temp_incidence_matrix)[idx])
}
temp_incidence_matrix=temp_incidence_matrix[-which_temp_vendog,-which_temp_vendog, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
flag=1
}
#RULE #1
rule1_active=c()
for (idx in 1:dim(temp_incidence_matrix)[1])
if (temp_incidence_matrix[idx,idx]==1)
rule1_active=c(idx,rule1_active)
if (length(rule1_active)>0)
{
VFEED=c(VFEED,rownames(temp_incidence_matrix)[rule1_active])
temp_incidence_matrix=temp_incidence_matrix[-rule1_active,-rule1_active, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
flag=1
}
}#end flag
#break if incidence matrix is empty
if (dim(temp_incidence_matrix)[1]==0) break
#RULE #4
#remove most populated (#1 in rows * (times) #1 in cols)
temp_rowSums_vendog=rowSums(temp_incidence_matrix)
temp_colSums_vendog=colSums(temp_incidence_matrix)
which_max_temp=which.max(temp_rowSums_vendog*temp_colSums_vendog)
VFEED=c(VFEED,rownames(temp_incidence_matrix)[which_max_temp])
temp_incidence_matrix=temp_incidence_matrix[-which_max_temp,-which_max_temp, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
}
#separate VFEED from VSIM, and order VSIM
VSIM=c()
temp_incidence_matrix=incidence_matrix
which_inactive_vendog_index=which(rownames(temp_incidence_matrix) %in% VFEED)
temp_incidence_matrix=temp_incidence_matrix[-which_inactive_vendog_index,-which_inactive_vendog_index, drop=F]
if (dim(temp_incidence_matrix)[1]>0) while(1){
if (dim(temp_incidence_matrix)[1]==0) break
temp_vendog=rowSums(temp_incidence_matrix)
which_temp_vendog=(temp_vendog==0)
if (any(which_temp_vendog))
{
VSIM=c(VSIM,rownames(temp_incidence_matrix)[which_temp_vendog])
temp_incidence_matrix=temp_incidence_matrix[! which_temp_vendog,! which_temp_vendog, drop=F]
if (dim(temp_incidence_matrix)[1]==0) break
} else {
stop(paste0('LOAD_MODEL(): cannot reduce incidence matrix.'))
}
}
#append VFEED to VSIM
VSIM=c(VSIM,VFEED)
return(list(
vsim=VSIM,
vfeed=VFEED
))
}
#Tarjan support funs
#see Tarjan's strongly connected components algorithm
.TarjanBlocksExtraction <- function(incidence_matrix)
{
#local supporting environment
localT=new.env()
#copy incidence matrix into envornment
localT$incidence_matrix=incidence_matrix
nvar=dim(incidence_matrix)[1] #V
localT$stack=c() #S
localT$lists=list()
#refs:
#tarjanMatrix[v,1] == v.index, -1==undefined
#tarjanMatrix[v,2] == v.lowlink
#tarjanMatrix[v,3] == v.onStack
localT$tarjanMatrix=matrix(0,nrow=nvar,ncol=3)
localT$tarjanMatrix[,1]=-1
localT$index=0 #index != v.index
for (vv in 1:nvar)
{
if (localT$tarjanMatrix[vv,1]==-1)
.TarjanStrongConnect(vv,localT)
}
return(localT)
}
.TarjanStrongConnect <- function(vv,localT)
{
localT$tarjanMatrix[vv,1]=localT$index
localT$tarjanMatrix[vv,2]=localT$index
localT$index=localT$index+1
localT$stack=c(vv,localT$stack)
localT$tarjanMatrix[vv,3]=1
destvars=which(localT$incidence_matrix[,vv]==1)
#we exploded recursive function by 3 levels to avoid R limitation on stack
if (length(destvars)>0)
for (ww in destvars)
{
#ww.index indefined
if (localT$tarjanMatrix[ww,1]==-1)
{
#_______________________________________
vv_old=vv
ww_old=ww
vv=ww
localT$tarjanMatrix[vv,1]=localT$index
localT$tarjanMatrix[vv,2]=localT$index
localT$index=localT$index+1
localT$stack=c(vv,localT$stack)
localT$tarjanMatrix[vv,3]=1
destvars=which(localT$incidence_matrix[,vv]==1)
if (length(destvars)>0)
for (ww in destvars)
{
if (localT$tarjanMatrix[ww,1]==-1)
{
#_______________________________________
vv_old2=vv
ww_old2=ww
vv=ww
localT$tarjanMatrix[vv,1]=localT$index
localT$tarjanMatrix[vv,2]=localT$index
localT$index=localT$index+1
localT$stack=c(vv,localT$stack)
localT$tarjanMatrix[vv,3]=1
destvars=which(localT$incidence_matrix[,vv]==1)
if (length(destvars)>0)
for (ww in destvars)
{
if (localT$tarjanMatrix[ww,1]==-1)
{
#_______________________________________
vv_old3=vv
ww_old3=ww
vv=ww
localT$tarjanMatrix[vv,1]=localT$index
localT$tarjanMatrix[vv,2]=localT$index
localT$index=localT$index+1
localT$stack=c(vv,localT$stack)
localT$tarjanMatrix[vv,3]=1
destvars=which(localT$incidence_matrix[,vv]==1)
if (length(destvars)>0)
for (ww in destvars)
{
if (localT$tarjanMatrix[ww,1]==-1)
{
#_______________________________________
#vv_old=vv
#vv=ww
.TarjanStrongConnect(ww,localT)
#vv=vv_old
#_______________________________________
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,2])
} else if (localT$tarjanMatrix[ww,3]==1)
{
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,1])
}
}
if (localT$tarjanMatrix[vv,2]==localT$tarjanMatrix[vv,1])
{
listsLength=length(localT$lists)+1
outputList=c()
flag=0
while (flag!=vv)
{
ww=localT$stack[1]
localT$stack=localT$stack[-1]
localT$tarjanMatrix[ww,3]=0
outputList=c(outputList,ww)
flag=ww
}
localT$lists[[listsLength]]=outputList
}
ww=ww_old3
vv=vv_old3
#_______________________________________
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,2])
} else if (localT$tarjanMatrix[ww,3]==1)
{
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,1])
}
}
if (localT$tarjanMatrix[vv,2]==localT$tarjanMatrix[vv,1])
{
listsLength=length(localT$lists)+1
outputList=c()
flag=0
while (flag!=vv)
{
ww=localT$stack[1]
localT$stack=localT$stack[-1]
localT$tarjanMatrix[ww,3]=0
outputList=c(outputList,ww)
flag=ww
}
localT$lists[[listsLength]]=outputList
}
ww=ww_old2
vv=vv_old2
#_______________________________________
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,2])
} else if (localT$tarjanMatrix[ww,3]==1)
{
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,1])
}
}
if (localT$tarjanMatrix[vv,2]==localT$tarjanMatrix[vv,1])
{
listsLength=length(localT$lists)+1
outputList=c()
flag=0
while (flag!=vv)
{
ww=localT$stack[1]
localT$stack=localT$stack[-1]
localT$tarjanMatrix[ww,3]=0
outputList=c(outputList,ww)
flag=ww
}
localT$lists[[listsLength]]=outputList
}
ww=ww_old
vv=vv_old
#_______________________________________
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,2])
} else if (localT$tarjanMatrix[ww,3]==1)
{
localT$tarjanMatrix[vv,2]=min(localT$tarjanMatrix[vv,2],localT$tarjanMatrix[ww,1])
}
}
if (localT$tarjanMatrix[vv,2]==localT$tarjanMatrix[vv,1])
{
listsLength=length(localT$lists)+1
outputList=c()
flag=0
while (flag!=vv)
{
ww=localT$stack[1]
localT$stack=localT$stack[-1]
localT$tarjanMatrix[ww,3]=0
outputList=c(outputList,ww)
flag=ww
}
localT$lists[[listsLength]]=outputList
}
}
#return list of unknown fun names, case ignored
.unknownFunsNames <- function(inputS=NULL,reservedKeyw)
{
allFunNames=.extractFunsNames(inputS)
return( allFunNames[! (toupper(allFunNames) %in% reservedKeyw)])
}
# exported core funs -----------------------------------------------------------
# PRINT SUMMARY code -----------------------------------------------------------
print.BIMETS_MODEL <- function(x=NULL,...)
{
model=x
if (! inherits(model, "BIMETS_MODEL")) stop("print.BIMETS_MODEL(): model object is not a BIMETS model.")
cat(paste0('\nBIMETS MODEL\n'))
cat(paste0('-----------------------------------\n'))
cat(paste0(sprintf("%-25s",'name:'),model$modelName,'\n'))
cat(paste0(sprintf("%-25s",'built with bimets:'),ifelse(is.null(model$bimets_version),'unknown',model$bimets_version),'\n'))
cat(paste0(sprintf("%-25s",'behaviorals:'),(model$totNumEqs),'\n'))
cat(paste0(sprintf("%-25s",'identities:'),(model$totNumIds),'\n'))
cat(paste0(sprintf("%-25s",'coefficients:'),(model$eqCoeffNum),'\n'))
tryCatch({
.CHECK_MODEL_DATA(model,showWarnings=FALSE)
cat(paste0(sprintf("%-25s",'model data:'),"OK",'\n'))
},error=function(e){cat(paste0(sprintf("%-25s",'model data:'),"not OK",' :: ',e$message,"\n")) })
is_lead=FALSE
if (model$max_lead>0) is_lead=TRUE
cat(paste0(sprintf("%-25s",'forward looking:'),(is_lead),'\n'))
totCoeffEstimated=0
if (length(model$behaviorals)>0) for (idxEq in 1:length(model$behaviorals))
{
totCoeffEstimated=totCoeffEstimated+length(model$behaviorals[[idxEq]]$coefficients)
}
fullyEstimated=ifelse(totCoeffEstimated<model$eqCoeffNum,FALSE,TRUE)
cat(paste0(sprintf("%-25s",'fully estimated:'),(fullyEstimated),'\n'))
simulated=FALSE
if (! is.null(model$simulation))
{
namesSim=names(model$simulation)
namesSim=namesSim[-which(namesSim=='__SIM_PARAMETERS__')]
if (length(base::setdiff(model$vendog,namesSim))==0)
simulated=TRUE
}
cat(paste0(sprintf("%-25s",'fully simulated:'),(simulated),'\n'))
renormed=FALSE
if (! is.null(model$renorm))
{
if (!is.null(model$renorm$TARGET))
renormed=TRUE
}
cat(paste0(sprintf("%-25s",'renormed:'),(renormed),'\n'))
stoch_simulated=FALSE
if (! is.null(model$stochastic_simulation))
{
namesSim=names(model$stochastic_simulation)
namesSim=namesSim[-which(namesSim=='__STOCH_SIM_PARAMETERS__')]
if (length(base::setdiff(model$vendog,namesSim))==0)
stoch_simulated=TRUE
}
cat(paste0(sprintf("%-25s",'fully stochastic sim.:'),(stoch_simulated),'\n'))
optimized=FALSE
if (! is.null(model$optimize))
{
if (!is.null(model$optimize$realizationsToKeep))
optimized=TRUE
}
cat(paste0(sprintf("%-25s",'optimized:'),(optimized),'\n'))
}
summary.BIMETS_MODEL <- function(object,...)
{
return(print.BIMETS_MODEL(object,...))
}
# LOAD MODEL code --------------------------------------------------------------
LOAD_MODEL <- function(modelFile=NULL,
modelText=NULL,
quietly=FALSE,
oldStyleModel=FALSE,
...)
{
#rawData: original text file
#cleanModel: rawData without MODEL, END, comments and trim spaces
#totNumEqs: equations count
#totNumIds: identities count ("same id multiple IF>" counts 1)
#totNumCoeff: coefficients count
#behaviorals: contains data of behavioral definition
#identities: contains data of identity definition
#max_lag: contains max lag required for all eqs
#oldStyleModel removes starting dollar signs if there
# is another dollar sign at the end of the line
#main output
model=list()
class(model)='BIMETS_MODEL'
#get regex definitions
regExDefs=.RegExGlobalDefinition()
reservedKeyw=regExDefs$reservedKeyw
symOnEqCleaner=regExDefs$symOnEqCleaner
symOnIfCleaner=regExDefs$symOnIfCleaner
allowedCharOnName=regExDefs$allowedCharOnName
allowedCharOnNameToken=regExDefs$allowedCharOnNameToken
charsOnNumbs=regExDefs$charsOnNumbs
charsOnNumWithSign=regExDefs$charsOnNumWithSign
strongCharOnNumbs=regExDefs$strongCharOnNumbs
strongCharOnNumbsWithSign=regExDefs$strongCharOnNumbsWithSign
allowedLhsEQfuns=regExDefs$allowedLhsEQfuns
allowedLhsEQfunsPub=regExDefs$allowedLhsEQfunsPub
#check arg
if (!(is.logical(quietly))) stop('LOAD_MODEL(): "quietly" must be TRUE or FALSE.')
#input is a file
if (is.null(modelText))
{
#file exists?
if (is.null(modelFile) || !is.character(modelFile) || !file.exists(modelFile))
stop('LOAD_MODEL(): model file "',as.character(modelFile),'" not found.')
modelName=modelFile
#read file
tryCatch({
rawData=readLines(modelFile,warn=FALSE)
},error=function(e){stop('LOAD_MODEL(): cannot read the model file. ',e$message) })
} else
{
#input is text
modelName=substitute(modelText)
#deal with MS-Win carriage
modelText=gsub('\r\n','\n',modelText)
#get lines
rawData=strsplit(modelText,'\n')[[1]]
}
#check consistence
if (length(rawData)==0) stop('LOAD_MODEL(): empty model file.')
model$rawData=rawData
#trim leading/trailing spaces
cleanModel=gsub("^\\s+|\\s+$", "", rawData)
#no code in file
if (length(cleanModel)==0) stop('LOAD_MODEL(): empty model file.')
#remove extra $ if required
if (oldStyleModel==TRUE)
{
for (idxR in 1:length(cleanModel))
{
#if double dollar sign then it is a comment
if (grepl('^\\s*\\$.*\\$\\s*$',cleanModel[idxR]))
next
#...else remove first $
cleanModel[idxR]=gsub("^\\s*\\$", "", cleanModel[idxR])
}
}
#remove empty lines
emptyLinesIdx=which(cleanModel=='')
if (length(emptyLinesIdx)>0) cleanModel=cleanModel[-emptyLinesIdx]
if (cleanModel[1]!='MODEL' || cleanModel[length(cleanModel)]!='END')
stop('LOAD_MODEL(): model file must begin with MODEL and must end with END keywords.')
#again trim leading/trailing spaces
cleanModel=gsub("^\\s+|\\s+$", "", cleanModel)
#remove comments (line starting with $ or COMMENT) and first/last line (MODEL|END)
commentsIndexes=grep("^(\\$|COMMENT\\s*>)",cleanModel,ignore.case=TRUE)
if (length(commentsIndexes)>0) cleanModel=cleanModel[-commentsIndexes]
cleanModel=cleanModel[-1]
cleanModel=cleanModel[-length(cleanModel)]
if (length(grep("\\$",cleanModel))>0)
stop('LOAD_MODEL(): dollar symbol (i.e. a comment) allowed only at the beginning of a line.\nCheck line "',cleanModel[grep("\\$",cleanModel)[1]],'"')
#eqs and ids num
totNumEqs=0
totNumIds=0
#collect keyword indexes
behavioralIndexes=grep("^(EQUATION|BEHAVIORAL)\\s*>",cleanModel, ignore.case=TRUE)
identityIndexes=grep("^IDENTITY\\s*>",cleanModel, ignore.case=TRUE)
eqIndexes=grep("^EQ\\s*>",cleanModel, ignore.case=TRUE)
coeffIndexes=grep("^COEFF\\s*>",cleanModel, ignore.case=TRUE)
storeIndexes=grep("^STORE\\s*>",cleanModel, ignore.case=TRUE)
pdlIndexes=grep("^PDL\\s*>",cleanModel, ignore.case=TRUE)
restrictIndexes=grep("^RESTRICT\\s*>",cleanModel, ignore.case=TRUE)
errorIndexes=grep("^ERROR\\s*>",cleanModel, ignore.case=TRUE)
ifIndexes=grep("^IF\\s*>",cleanModel, ignore.case=TRUE)
ivIndexes=grep("^IV\\s*>",cleanModel, ignore.case=TRUE)
#sorted indexes of all keywords
kwIdx=sort(c(length(cleanModel)+1,
behavioralIndexes,
identityIndexes,
eqIndexes,
coeffIndexes,
storeIndexes,
pdlIndexes,
restrictIndexes,
errorIndexes,
ifIndexes,
ivIndexes))
#sorted indexes of eq keywords
eqIdenDefIdx=sort(c(length(cleanModel)+1,
behavioralIndexes,
identityIndexes))
#coeff num
totNumCoeff=0
#analyze code behaviorals -----------------------------------------------------------------------------
model$behaviorals=list()
#cycle and extract all behaviorals
if (length(behavioralIndexes)>0) for(idxBI in 1:length(behavioralIndexes))
{
#empty tmp behavioral to be added to model list
behavioralTmp=list()
#...we extract all code between two behavioral definitions
#get next keyword definition index
nextKwIdx=min(kwIdx[which(kwIdx>behavioralIndexes[idxBI])])
#get next behavioral definition index, needed to check COEFF exists
nextDefIdx=min(eqIdenDefIdx[which(eqIdenDefIdx>behavioralIndexes[idxBI])])
#read and trim all lines of behavior definition
behavioralRaw=paste(cleanModel[behavioralIndexes[idxBI]:(nextKwIdx-1)],collapse=' ')
behavioralRaw=gsub("^(EQUATION|BEHAVIORAL)\\s*>", "", behavioralRaw, ignore.case=TRUE)
behavioralRaw=gsub("^\\s+|\\s+$", "", behavioralRaw)
#get behavioral name (split if TSRANGE defined)
behavioralName=gsub("^\\s+|\\s+$", "",strsplit(behavioralRaw,'TSRANGE')[[1]][1])
if (is.na(behavioralName) || nchar(behavioralName)==0)
stop('LOAD_MODEL(): unknown behavioral name in line: "',cleanModel[behavioralIndexes[idxBI]],'".')
#check name is compliant with regex
if (length(grep(allowedCharOnName,behavioralName))==0)
stop('LOAD_MODEL(): invalid behavioral name: "',behavioralName,'".')
#check TSRANGE inline definition
if (length(grep('TSRANGE',behavioralRaw))>0)
{
tryCatch({
#get text after TSRANGE kw then split with spaces
behavioralTsrange=suppressWarnings(as.numeric(strsplit(gsub("^\\s+|\\s+$", "",strsplit(behavioralRaw,'TSRANGE')[[1]][2]),'\\s+')[[1]]))
if (any(! is.finite(behavioralTsrange))) stop()
if (any(behavioralTsrange<=0)) stop()
if (any(behavioralTsrange %% 1 != 0)) stop()
if (length(behavioralTsrange)!=4) stop()
},error=function(e){
stop('LOAD_MODEL(): invalid TSRANGE in line: "',behavioralRaw,'".')})
} else behavioralTsrange=NA
#check behavioral has the COEFF definition
coeffLocalIdx=which(coeffIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
if (length(coeffLocalIdx)==0) stop('LOAD_MODEL(): no COEFF definition in behavioral "',behavioralName,'".')
if (length(coeffLocalIdx)>1) stop('LOAD_MODEL(): multiple COEFF definitions in behavioral "',behavioralName,'".')
#read all lines of coeff definition
nextKwIdx=min(kwIdx[which(kwIdx>coeffIndexes[coeffLocalIdx])])
coeffRaw=paste(cleanModel[coeffIndexes[coeffLocalIdx]:(nextKwIdx-1)],collapse=' ')
coeffRaw=gsub("^COEFF\\s*>", "", coeffRaw, ignore.case=TRUE)
coeffRaw=gsub("^\\s+|\\s+$", "", coeffRaw)
#split and remove duplicates
coeff=unique(strsplit(coeffRaw,'\\s+')[[1]])
#check coeef have allowed names
if (any(! grepl(allowedCharOnName,coeff))) stop('LOAD_MODEL(): invalid name in COEFF definition "',coeffRaw,'" in behavioral "',behavioralName,'".')
coeffNum=length(coeff)
totNumCoeff=totNumCoeff+coeffNum
if (coeffNum==0) stop('LOAD_MODEL(): no COEFF definition in behavioral "',behavioralName,'".')
#check behavioral has EQ definition
eqLocalIdx=which(eqIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
if (length(eqLocalIdx)==0) stop('LOAD_MODEL(): no EQ definition in behavioral "',behavioralName,'".')
if (length(eqLocalIdx)>1) stop('LOAD_MODEL(): multiple EQ definitions in behavioral "',behavioralName,'".')
#read all lines of EQ definition
nextKwIdx=min(kwIdx[which(kwIdx>eqIndexes[eqLocalIdx])])
eqRaw=paste(cleanModel[eqIndexes[eqLocalIdx]:(nextKwIdx-1)],collapse=' ')
eqRaw=gsub("^EQ\\s*>", "", eqRaw, ignore.case=TRUE)
eqRaw=gsub("\\s*", "", eqRaw)
#check unknown funs names
unknownFuns=.unknownFunsNames(eqRaw,reservedKeyw)
if (length(unknownFuns)>0) stop('LOAD_MODEL(): unsupported functions in EQ definition: "',eqRaw,'" in behavioral "',behavioralName,'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
#check EQ is non trivial
if (nchar(eqRaw)==0 || !grepl('=',eqRaw))
stop('LOAD_MODEL(): syntax error in behavioral "',behavioralName,'" in EQ definition: "',eqRaw,'".')
#trim and extract symbol names from EQ
#we keep dependent
namesOnEq=strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnEqCleaner,' ',eqRaw,ignore.case=TRUE)),'\\s+')[[1]]
#check EQ is non trivial
if ( length(namesOnEq)==0 )
stop('LOAD_MODEL(): syntax error in behavioral "',behavioralName,'" in EQ definition: "',eqRaw,'".')
#remove numbers from names
rmvNumOnEqIdx=c()
for (idxNamesOnEq in 1:length(namesOnEq)) {
if (length(grep(strongCharOnNumbs,namesOnEq[idxNamesOnEq]))>0)
{
rmvNumOnEqIdx=c(rmvNumOnEqIdx,idxNamesOnEq)
}
}
if (length(rmvNumOnEqIdx)>0) namesOnEq=namesOnEq[-rmvNumOnEqIdx]
#check "=" exists
eqRawSplitted=strsplit(eqRaw,'\\=')[[1]]
if (length(eqRawSplitted)!=2) stop('LOAD_MODEL(): syntax error in behavioral "',behavioralName,'" in EQ definition: "',eqRaw,'".')
rhsExp=eqRawSplitted[2]
lhsExp=eqRawSplitted[1]
if (lhsExp=='') stop('LOAD_MODEL(): syntax error in behavioral "',behavioralName,'" in EQ definition: "',eqRaw,'".')
lhsFun=NULL
#find lhs func
tryCatch({
lhsFun=.parseLhsEQ(lhsExp,allowedLhsEQfuns)
},error=function(err){
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" in behavioral "',behavioralName,'".')})
# lhs behavioral ------------------------------------------------
#check lhs fun syntax
if (lhsFun$funName=='I')
{
#check EQ contains behavioral name
if (lhsFun$args!=behavioralName)
stop('LOAD_MODEL(): LHS of EQ definition: "',eqRaw,'" must contain only the behavioral name "',behavioralName,'" or the allowed uppercase LHS functions: ',paste0(paste0(allowedLhsEQfunsPub,'()'),collapse=', '))
if (lhsExp!=paste0(behavioralName))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',behavioralName,'" are allowed on the LHS of EQ definition, e.g. EQ> ',behavioralName,'=...')
} else if (lhsFun$funName=='LOG')
{
if (lhsFun$argsCount!=1 || lhsFun$args!=behavioralName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the behavioral "',behavioralName,'". If the LOG of the endogenous variable is requested please try the following: "LOG(',behavioralName,')"')
if (lhsExp!=paste0('LOG(',behavioralName,')'))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',behavioralName,'" are allowed on the LHS of EQ definition, e.g. EQ> LOG(',behavioralName,')=...')
} else if (lhsFun$funName=='EXP')
{
if (lhsFun$argsCount!=1 || lhsFun$args!=behavioralName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the behavioral "',behavioralName,'". If the EXP of the endogenous variable is requested please try the following: "EXP(',behavioralName,')"')
if (lhsExp!=paste0('EXP(',behavioralName,')'))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',behavioralName,'" are allowed on the LHS of EQ definition, e.g. EQ> EXP(',behavioralName,')=...')
} else if (lhsFun$funName=='TSDELTA' || lhsFun$funName=='DEL')
{
if (lhsFun$argsCount>2 || lhsFun$args[1]!=behavioralName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the behavioral "',behavioralName,'". If the TSDELTA of the endogenous variable is requested please try the following: "TSDELTA(',behavioralName,')" or "TSDELTA(',behavioralName,',n)"')
if (lhsExp!=paste0(lhsFun$funName,'(',behavioralName,',',lhsFun$args[2],')') && lhsExp!=paste0(lhsFun$funName,'(',behavioralName,')'))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',behavioralName,'" are allowed on the LHS of EQ definition, e.g. EQ> TSDELTA(',behavioralName,',n)=...')
} else if (lhsFun$funName=='TSDELTAP' )
{
if (lhsFun$argsCount>2 || lhsFun$args[1]!=behavioralName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the behavioral "',behavioralName,'". If the TSDELTAP of the endogenous variable is requested please try the following: "TSDELTAP(',behavioralName,')" or "TSDELTAP(',behavioralName,',n)"')
if (lhsExp!=paste0(lhsFun$funName,'(',behavioralName,',',lhsFun$args[2],')') && lhsExp!=paste0(lhsFun$funName,'(',behavioralName,')') )
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',behavioralName,'" are allowed on the LHS of EQ definition, e.g. EQ> TSDELTAP(',behavioralName,',n)=...')
} else if (lhsFun$funName=='TSDELTALOG' )
{
if (lhsFun$argsCount>2 || lhsFun$args[1]!=behavioralName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" in behavioral "',behavioralName,'". If the TSDELTALOG of the endogenous variable is requested please try the following: "TSDELTALOG(',behavioralName,')" or "TSDELTALOG(',behavioralName,',n)"')
if (lhsExp!=paste0(lhsFun$funName,'(',behavioralName,',',lhsFun$args[2],')') && lhsExp!=paste0(lhsFun$funName,'(',behavioralName,')') )
stop('LOAD_MODEL(): syntax error in behavioral "',behavioralName,'" in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',behavioralName,'" are allowed on the LHS of EQ definition, e.g. EQ> TSDELTALOG(',behavioralName,',n)=...')
}
#check EQ contains COEFFs
for(coeffTmp in coeff) if (length(grep(allowedCharOnName,coeffTmp))==0)
stop('LOAD_MODEL(): invalid coefficient name "',coeffTmp,'" in COEFF definition of behavioral: "',behavioralName,'".')
for(coeffTmp in coeff) if (! (coeffTmp %in% namesOnEq) )
stop('LOAD_MODEL(): coefficient "',coeffTmp,'" not found in EQ definition: "',eqRaw,'".')
if (! .checkExpression(rhsExp)) stop('LOAD_MODEL(): syntax error in behavioral: "',behavioralName,'" in RHS of EQ definition: "',eqRaw,'".')
#remove coeff from EQ components names
rmvCoeffOnEqIdx=c()
for (idxNamesOnEq in 1:length(namesOnEq)) {
if (namesOnEq[idxNamesOnEq] %in% coeff)
{
rmvCoeffOnEqIdx=c(rmvCoeffOnEqIdx,idxNamesOnEq)
}
}
if (!(all(namesOnEq[rmvCoeffOnEqIdx]==coeff)))
stop('LOAD_MODEL(): in behavioral "',behavioralName,'", coefficients in EQ definition: "',eqRaw,'" must appear in the same order as in the COEFF definition: "',paste(coeff,collapse=', '),'".')
if (length(rmvCoeffOnEqIdx)>0) namesOnEq=namesOnEq[-rmvCoeffOnEqIdx]
#check components name
for (idxNOEQ in 1:length(namesOnEq)) {
if (length(grep(allowedCharOnName,namesOnEq[idxNOEQ]))==0)
{
stop('LOAD_MODEL(): syntax error in behavioral "',behavioralName,'" in EQ definition: "',eqRaw,'". The following symbol cannot be a variable name: "',namesOnEq[idxNOEQ],'".')
}
}
#normalize regressors
for(coeffTmp in coeff)
{
#if is intercept (isolated coeff)
if (!grepl(paste0(coeffTmp,'\\*'),rhsExp))
{
#convert intercept: coeff0+ -> coeff0*1+
rhsExp=gsub(paste0(coeffTmp,'\\+'),paste0(coeffTmp,'*1+'),rhsExp)
#+coeff0 at the end -> +coeff0*1
rhsExp=gsub(paste0(coeffTmp,'$'),paste0(coeffTmp,'*1'),rhsExp)
#coeff0 at the start -> +coeff0
rhsExp=gsub(paste0('^',coeffTmp),paste0('+',coeffTmp),rhsExp)
}
#in case rhs start with coeff without sign
rhsExp=gsub(paste0('^',coeffTmp),paste0('+',coeffTmp),rhsExp)
}
for(coeffTmp in coeff) if (length(grep(paste0('(\\+)',coeffTmp,'\\*'),rhsExp))==0 )
stop('LOAD_MODEL(): in behavioral "',behavioralName,'", please provide EQ "',eqRaw,'" in form of a linear combination of coefficients: fix coeff. "',coeffTmp,'".')
#split using coeffs and get EQ regressors
eqRegressorsNames=strsplit(rhsExp,paste0('(\\+)(',paste(coeff,collapse='|'),')\\*'))[[1]]
if (length(eqRegressorsNames)<2) stop('LOAD_MODEL(): in behavioral "',behavioralName,'", regressors count error in EQ definition: "',eqRaw,'"')
if (eqRegressorsNames[1]!='')
stop('LOAD_MODEL(): in behavioral "',behavioralName,'", please provide EQ "',eqRaw,'" in form of a linear combination of coefficients.')
eqRegressorsNames=eqRegressorsNames[-1] #remove first void element
for (idxR in 1:length(eqRegressorsNames))
if (! .checkExpressionIsAtomic(eqRegressorsNames[idxR]))
stop('LOAD_MODEL(): in behavioral "',behavioralName,'", please provide EQ "',eqRaw,'" in form of a linear combination of coefficients: fix regressor "',eqRegressorsNames[idxR],'".')
if (length(eqRegressorsNames)!=length(coeff))
stop('LOAD_MODEL(): in behavioral "',behavioralName,'", regressors count in EQ definition: "',eqRaw,'" is different from coefficients count in COEFF definition: "',paste(coeff,collapse=', '),'".')
#check if duplicated regressor
if (any(duplicated(eqRegressorsNames)))
stop('LOAD_MODEL(): in behavioral "',behavioralName,'", duplicated regressor "',paste(eqRegressorsNames[which(duplicated(eqRegressorsNames))],collapse=' '),'" in EQ definition: "',eqRaw,'".')
#check unique intercept
flagSC=FALSE
for(regrTmp in eqRegressorsNames)
{
if (grepl(strongCharOnNumbs,regrTmp))
{
if (flagSC) stop('LOAD_MODEL(): in behavioral "',behavioralName,'", multiple intercepts defined in EQ: "',eqRaw,'"' )
flagSC=TRUE
}
}
#check behavioral has STORE definition
storeLocalIdx=which(storeIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
storeVarName=NULL
storePosition=NULL
if (length(storeLocalIdx)>0)
{
if (length(storeLocalIdx)>1) stop('LOAD_MODEL(): multiple STORE definitions in behavioral "',behavioralName,'".')
#read all lines of store definition
nextKwIdx=min(kwIdx[which(kwIdx>storeIndexes[storeLocalIdx])])
storeRaw=paste(cleanModel[storeIndexes[storeLocalIdx]:(nextKwIdx-1)],collapse=' ')
storeRaw=gsub("^STORE\\s*>", "", storeRaw, ignore.case=TRUE)
storeRaw=gsub("\\s*", "", storeRaw)
#get store var name and position
storeSplit=strsplit(storeRaw,'\\(')[[1]]
if (length(storeSplit)!=2)
stop('LOAD_MODEL(): syntax error in STORE definition: "',storeRaw,'" in behavioral "',behavioralName,'".')
storeVarName=gsub("\\s*", "", storeSplit[1])
if (length(grep(allowedCharOnName,storeVarName))==0)
stop('LOAD_MODEL(): invalid variable name in STORE definition: "',storeRaw,'" in behavioral "',behavioralName,'".')
#STORE location must be positive integer
if (length(grep("^\\s*[0]*[0-9]*\\s*\\)$",storeSplit[2]))==0)
stop('LOAD_MODEL(): syntax error in STORE definition: "',storeRaw,'" in behavioral "',behavioralName,'".')
storePosition=as.numeric(gsub('\\)','',storeSplit[2]))
if (storePosition<0)
stop('LOAD_MODEL(): unknown error on retrieving STORE position in "',storeRaw,'" in behavioral "',behavioralName,'".')
}
#check behavioral has PDL definition
#pdlLocalIdx contains lines indexes of pdl in behavioral
pdlLocalIdx=which(pdlIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
pdlRaw=NULL
bm_pdlMatrix=NULL
bm_pdlRestrictionMatrix=c()
bm_pdlRestrictionVector=c()
#backUp old coeff and eqRegressorsNames
coeffOriginal=coeff
eqRegressorsNamesOriginal=eqRegressorsNames
#we have PDL definitions
if (length(pdlLocalIdx)>0)
{
#analyze all PDL definitions
pdlRaw=''
for (pdlLLidx in 1:length(pdlLocalIdx))
{
#read all lines of PDL definition
nextKwIdx=min(kwIdx[which(kwIdx>pdlIndexes[pdlLocalIdx[pdlLLidx]])])
#e.g. pdlRawSingle="PDL> C06 2 14 F"
#clean...
pdlRawSingle=paste(cleanModel[pdlIndexes[pdlLocalIdx[pdlLLidx]]:(nextKwIdx-1)],collapse=';')
pdlRawSingle=gsub("^PDL\\s*>", "", pdlRawSingle, ignore.case=TRUE)
pdlRawSingle=gsub("^\\s*|\\s*$", "", pdlRawSingle)
#e.g. pdlRaw="C07 2 14 F;C06 2 14 F;"
pdlRaw=paste0(pdlRawSingle,';',pdlRaw)
}
#analyze pdlRaw
pdlComponents=strsplit(pdlRaw,';')[[1]]
if (length(pdlComponents)<1)
stop('LOAD_MODEL(): NULL length in PDL definition "',pdlRaw,'" in behavioral "',behavioralName,'".')
#create empty list
bm_pdl=list()
#following 'bm_pdlMatrix' matrix will have:
#first row is 1 if restriction applies to i-th coefficient
#second row and third row have degree and lag values
#4th row is 1 if N
#5th row is 1 if F
bm_pdlMatrix=matrix(rep(0,5*length(coeff)),nrow=5,ncol=length(coeff))
for (idxPC in 1:length(pdlComponents ))
{
#split with spaces " C06 2 14 F" -> c('C06',2,14,'F')
pdlSingleElement=strsplit(pdlComponents[idxPC],'\\s+')[[1]]
if ((length(pdlSingleElement)<3) || (length(pdlSingleElement)>5))
stop('LOAD_MODEL(): syntax error in PDL definition "',pdlComponents[idxPC],'" in behavioral "',behavioralName,'". Usage: PDL> coeff degree laglength [N] [F].')
#check coefficient exists
if ( ! (pdlSingleElement[1] %in% coeff))
stop('LOAD_MODEL(): unknown coefficient "',pdlSingleElement[1],'" in PDL definition in behavioral "',behavioralName,'".')
coeffPos=which(coeff==pdlSingleElement[1])
bm_pdlMatrix[1,coeffPos]=1
#PDL on constant term throws an error
if (grepl(strongCharOnNumbs,eqRegressorsNames[coeffPos]))
{
stop('LOAD_MODEL(): cannot expand a PDL on a constant term: coeff. "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
}
#deal with degree
tmpV=as.numeric(pdlSingleElement[2])
if (
( ! is.finite(tmpV)) ||
(length(tmpV)==0) ||
(!((tmpV %% 1) == 0) ) ||
(!(tmpV >-1))
) stop('LOAD_MODEL(): polynomial degree must be a non-negative integer in PDL definition of coefficient "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
bm_pdlMatrix[2,coeffPos]=tmpV
#deal with laglength
tmpV=as.numeric(pdlSingleElement[3])
if (
( ! is.finite(tmpV)) ||
(length(tmpV)==0) ||
(!((tmpV %% 1) == 0) ) ||
(!(tmpV >0))
) stop('LOAD_MODEL(): laglength must be a positive integer in PDL definition of coefficient "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
bm_pdlMatrix[3,coeffPos]=tmpV
if (bm_pdlMatrix[3,coeffPos]<=bm_pdlMatrix[2,coeffPos])
stop('LOAD_MODEL(): laglength must be greater than polynomial degree in PDL definition of coefficient "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
#deal with N/F
if (length(pdlSingleElement)>3)
{
tmpV=pdlSingleElement[4]
if (
(tmpV != 'N') &&
(tmpV != 'F')
) stop('LOAD_MODEL(): options must be "N" and/or "F" in PDL definition of coefficient "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
if (tmpV == 'N') bm_pdlMatrix[4,coeffPos]=1
if (tmpV == 'F') bm_pdlMatrix[5,coeffPos]=1
}
if (length(pdlSingleElement)>4)
{
tmpV=pdlSingleElement[5]
if (
(tmpV != 'N') &&
(tmpV != 'F')
) stop('LOAD_MODEL(): options must be "N" and/or "F" in PDL definition of coefficient "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
if (tmpV == 'N') bm_pdlMatrix[4,coeffPos]=1
if (tmpV == 'F') bm_pdlMatrix[5,coeffPos]=1
}
#check if PDL is 0 1 then error due to redundance
if (bm_pdlMatrix[2,coeffPos]==0 && bm_pdlMatrix[3,coeffPos]==1)
stop('LOAD_MODEL(): PDL with degree 0 and length 1 can be removed: coefficient "',pdlSingleElement[1],'" in behavioral "',behavioralName,'".')
}
#add lagged coefficient to coefficient list
for (pdlMatrixIdx in 1:length(coeffOriginal))
{
#coefficient has pdl
if (bm_pdlMatrix[1,pdlMatrixIdx]==1)
{
#insert required coefficient in list of coefficients
coeffToBeInserted=c()
eqCompToBeInserted=c()
#pdl length > 1 then insert
if (bm_pdlMatrix[3,pdlMatrixIdx]>1)
{
for (idxCoeffToBeIns in 1:(bm_pdlMatrix[3,pdlMatrixIdx]-1))
{
#e.g. coeffToBeInserted=C06_PDL_6
coeffToBeInserted=c(coeffToBeInserted,paste0(coeffOriginal[pdlMatrixIdx],'__PDL__',idxCoeffToBeIns))
#e.g. eqCompToBeInserted=LAG( (LAG(LOG(KSTAR))-LAG(LOG(KSTAR),2)) ,9)
eqCompToBeInserted=c(eqCompToBeInserted,paste0('TSLAG(',eqRegressorsNamesOriginal[pdlMatrixIdx],',',idxCoeffToBeIns,')'))
}
}
#new coefficients and new regressors will be inserted after original ones
idxIntoInsert=which(coeff==coeffOriginal[pdlMatrixIdx])
if (idxIntoInsert<length(coeff)) coeff=c(coeff[1:idxIntoInsert],coeffToBeInserted,coeff[(idxIntoInsert+1):length(coeff)])
else coeff=c(coeff[1:idxIntoInsert],coeffToBeInserted)
idxIntoInsert=which(eqRegressorsNames==eqRegressorsNamesOriginal[pdlMatrixIdx])
#warning: adding LAGs can duplicate regressors
#e.g. we have a MDL EQ with regressors (i) "p" and (ii) "LAG(p,1)" in a klein model
#if we have PDL on "p" when we expand we will have a duplicated regressor LAG(p,1).
#Now, if we also have a PDL on second original regressors (ii) LAG(p,1)
#we have to take the last LAG(p,1) in list as the insertion point for new regressors
#for PDL of (ii) "LAG(p,1)" (regressor must be different in model definition so last one is ok)
idxIntoInsert=idxIntoInsert[length(idxIntoInsert)]
if (idxIntoInsert<length(eqRegressorsNames)) eqRegressorsNames=c(eqRegressorsNames[1:idxIntoInsert],eqCompToBeInserted,eqRegressorsNames[(idxIntoInsert+1):length(eqRegressorsNames)])
else eqRegressorsNames=c(eqRegressorsNames[1:idxIntoInsert],eqCompToBeInserted)
}
}
#create PDL restriction matrix and vector (using Tartaglia)
for (pdlMatrixIdx in 1:length(coeffOriginal))
{
#coefficient has PDL
if (bm_pdlMatrix[1,pdlMatrixIdx]==1)
{
#pdllength > pdldegree+1 then insert row
if (bm_pdlMatrix[3,pdlMatrixIdx]>bm_pdlMatrix[2,pdlMatrixIdx]+1)
{
#get tartaglia coefficients
tmpTartagliaRow=.bm_tartaglia_pdl(bm_pdlMatrix[2,pdlMatrixIdx])
for(tartagliaIdx in 1:(bm_pdlMatrix[3,pdlMatrixIdx]-(bm_pdlMatrix[2,pdlMatrixIdx]+1)))
{
#create R matrix row
temp_row=rep(0,length(coeff))
idxCoeff=which(coeff==coeffOriginal[pdlMatrixIdx])
#insert tartaglia coeff starting from correct index
temp_row[(idxCoeff-1+tartagliaIdx):(idxCoeff+length(tmpTartagliaRow)-2+tartagliaIdx)]=tmpTartagliaRow
#e.g. bm_pdlRestrictionMatrix=(0 0 1 -2 1 0 0; 0 0 0 1 -2 1 0 )
bm_pdlRestrictionMatrix=rbind(bm_pdlRestrictionMatrix,temp_row)
bm_pdlRestrictionVector=c(bm_pdlRestrictionVector,0)
}
}
#check N
#put one row in matrix with 1 on original coeff (no LAGged) e.g. c02
if (bm_pdlMatrix[4,pdlMatrixIdx]==1 && bm_pdlMatrix[3,pdlMatrixIdx]>1)
{
temp_row=rep(0,length(coeff))
idxCoeff=which(coeff==coeffOriginal[pdlMatrixIdx])
temp_row[idxCoeff]=1
bm_pdlRestrictionMatrix=rbind(bm_pdlRestrictionMatrix,temp_row)
bm_pdlRestrictionVector=c(bm_pdlRestrictionVector,0)
}
#check F
#put one row in matrix with 1 on last LAGged coeff e.g. LAG(C02,4)
if (bm_pdlMatrix[5,pdlMatrixIdx]==1 && bm_pdlMatrix[3,pdlMatrixIdx]>1)
{
temp_row=rep(0,length(coeff))
idxCoeff=which(coeff==coeffOriginal[pdlMatrixIdx])
temp_row[idxCoeff+bm_pdlMatrix[3,pdlMatrixIdx]-1]=1
bm_pdlRestrictionMatrix=rbind(bm_pdlRestrictionMatrix,temp_row)
bm_pdlRestrictionVector=c(bm_pdlRestrictionVector,0)
}
#check N and F and length=2 -> error
if (bm_pdlMatrix[4,pdlMatrixIdx]==1 && bm_pdlMatrix[5,pdlMatrixIdx]==1 && bm_pdlMatrix[3,pdlMatrixIdx]==2)
{
stop('LOAD_MODEL(): redundant options "N" and "F" set in coefficient "',coeffOriginal[pdlMatrixIdx],'" with PDL of length 2 in behavioral "',behavioralName,'".')
}
}
}
}#endif pdl
if (! is.null(bm_pdlRestrictionMatrix))
{
rownames(bm_pdlRestrictionMatrix)=c()
colnames(bm_pdlRestrictionMatrix)=c()
}
if (! is.null(bm_pdlRestrictionVector))
{
rownames(bm_pdlRestrictionVector)=c()
colnames(bm_pdlRestrictionVector)=c()
}
#check behavioral has RESTRICT def
#RESTRICT> definition can span on several lines
#or have multiple defs separated by ";"
restrictLocalIdx=which(restrictIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
restrictRaw=NULL
if (length(restrictLocalIdx)>0)
{
#analyze all restrict definitions
restrictRaw=''
for (restrictLLidx in 1:length(restrictLocalIdx))
{
#read all lines of restrict definition
nextKwIdx=min(kwIdx[which(kwIdx>restrictIndexes[restrictLocalIdx[restrictLLidx]])])
restrictRawSingle=paste(cleanModel[restrictIndexes[restrictLocalIdx[restrictLLidx]]:(nextKwIdx-1)],collapse=';')
restrictRawSingle=gsub("^RESTRICT\\s*>", "", restrictRawSingle, ignore.case=TRUE)
restrictRawSingle=gsub("\\s*", "", restrictRawSingle)
#e.g. restrictRaw="C01+C02=0;C01+C03=0"
restrictRaw=paste0(restrictRawSingle,';',restrictRaw)
}
#analyze restrictRaw
restrictComponents=strsplit(restrictRaw,';')[[1]]
if (length(restrictComponents)<1) stop('LOAD_MODEL(): NULL length in restriction definition "',restrictRaw,' in behavioral "',behavioralName,'".')
#matrix R and vector r of restriction
bm_matrixR=c()
bm_vectorR=c()
for (idxRestricComp in 1:length(restrictComponents))
{
#split equal
restrComponentSplit=strsplit(restrictComponents[[idxRestricComp]],'\\=')[[1]]
#check equal signs count
if (length(restrComponentSplit)!=2)
stop('LOAD_MODEL(): syntax error in restriction "',restrictComponents[[idxRestricComp]],'" in behavioral "',behavioralName,'".\nUsage: "RESTRICT> alpha0 * coeff0 + ... + alphaN * coeffN = const".')
restrictionRHS=restrComponentSplit[2]
restrictionLHS=restrComponentSplit[1]
#here we replace LAG(COEFF,X) with COEFF_PDL_X in RESTRICT
if (! is.null(bm_pdlMatrix))
{
#find coeff with pdl
idxCoeffInPdlMatrix=which(bm_pdlMatrix[1,]==1)
#cycle coeff in pdl
for (idxLoopInPdlMatrix in idxCoeffInPdlMatrix)
for (idxReplaceLagInRestriction in 1:(bm_pdlMatrix[3,idxLoopInPdlMatrix]-1))
{
restrictionLHS=gsub(paste0('LAG\\(',coeffOriginal[idxLoopInPdlMatrix],',',idxReplaceLagInRestriction,'\\)'),
paste0(coeffOriginal[idxLoopInPdlMatrix],'__PDL__',idxReplaceLagInRestriction),
restrictionLHS)
}
}
#check RHS constant is a number
if (length(grep(strongCharOnNumbsWithSign,restrictionRHS))==0)
stop('LOAD_MODEL(): syntax error in restriction "',restrictComponents[[idxRestricComp]],'" in behavioral "',behavioralName,'".\nUsage: "RESTRICT> alpha0 * coeff0 + ... + alphaN * coeffN = const".')
#check LHS is linear comb of coeff
regExprRes=paste0('^((',
charsOnNumWithSign,paste0('\\*|\\+|-)?(',
paste0(coeff,collapse='|') ,')'),')+$')
if (length(grep(regExprRes,restrictionLHS))==0)
stop('LOAD_MODEL(): syntax error in restriction "',restrictComponents[[idxRestricComp]],'" in behavioral "',behavioralName,'".\nUsage: "RESTRICT> alpha0 * coeff0 + ... + alphaN * coeffN = const".')
bm_tmpRrow=c()
#exctract coeff multiplier in restriction
for (idxCoeff in 1:length(coeff))
{
tmpRegExp=gregexpr(paste0('(',charsOnNumWithSign,'\\*|\\+|-)?(',
coeff[idxCoeff],')(\\+|-|$)'),restrictionLHS)
#e.g. localMultiplier="+C02"
localMultiplierList=regmatches(restrictionLHS,tmpRegExp)
localMultiplier=localMultiplierList[[1]]
#duplicate coefficient in single restriction
if (length(localMultiplier)>1)
stop('LOAD_MODEL(): syntax error in restriction "',restrictComponents[[idxRestricComp]],'" in behavioral "',behavioralName,'".\nUsage: "RESTRICT> alpha0 * coeff0 + ... + alphaN * coeffN = const".')
if (length(localMultiplier)==1)
{
#coeff exists in restriction
localMultiplier=gsub(paste0('(\\*|',coeff[idxCoeff],'(\\+|-)?)'),'',localMultiplier)
#exctract value
if (localMultiplier=='+' || localMultiplier=='' ) {
localMultiplier=1
} else if (localMultiplier=='-')
{
localMultiplier=-1
} else {
localMultiplier=as.numeric(localMultiplier)
}
} else
{
localMultiplier=0
}
bm_tmpRrow=c(bm_tmpRrow,localMultiplier)
}
#e.g. C01+C02=0;C01+C03=0
#bm_vectorR=(0;0)
bm_vectorR=c(bm_vectorR,as.numeric(restrictionRHS))
#e.g. bm_matrixR=(0 1 1 0 0...; 0 1 0 1 0 ...)
bm_matrixR=rbind(bm_matrixR,bm_tmpRrow)
}#end cycle component of restriction
if (! is.null(bm_matrixR))
{
rownames(bm_matrixR)=c()
colnames(bm_matrixR)=c()
}
if (! is.null(bm_vectorR))
{
rownames(bm_vectorR)=c()
colnames(bm_vectorR)=c()
}
behavioralTmp$matrixR=bm_matrixR
behavioralTmp$vectorR=bm_vectorR
}#endif restrict
#get ERROR>
#check behavioral has ERROR def
errorLocalIdx=which(errorIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
errorRaw=NULL
errorType=NULL
errorDim=NULL
if (length(errorLocalIdx)>0)
{
if (length(errorLocalIdx)>1) stop('LOAD_MODEL(): multiple ERROR definitions in behavioral "',behavioralName,'".')
errorRaw=''
nextKwIdx=min(kwIdx[which(kwIdx>errorIndexes[errorLocalIdx])])
errorRaw=paste(cleanModel[errorIndexes[errorLocalIdx]:(nextKwIdx-1)],collapse=' ')
errorRaw=gsub("^ERROR\\s*>", "", errorRaw, ignore.case=TRUE)
errorRaw=gsub("^\\s*|\\s*$", "", errorRaw)
#catch auto(n) directive with n=1..9
if (length(grep('^AUTO\\([1-9]\\)',errorRaw))>0){
errorType='AUTO'
errorDim=gsub("AUTO\\(", "", errorRaw)
errorDim=as.numeric(gsub("\\)", "", errorDim))
if ((length(errorDim)==0) || ! is.finite(errorDim) || (errorDim<1 ) || (errorDim>9 ))
stop('LOAD_MODEL(): syntax error in ERROR definition "',errorRaw,'" in behavioral "',behavioralName,'". Usage: ERROR> AUTO(n), n=1..9')
} else {
stop('LOAD_MODEL(): syntax error in ERROR definition "',errorRaw,'" in behavioral "',behavioralName,'". Usage: ERROR> AUTO(n), n=1..9')
}
}
#check behavioral has IV> def
#IV can span on several lines or have several definitions separated by ";"
ivLocalIdx=which(ivIndexes %in% behavioralIndexes[idxBI]:(nextDefIdx-1))
ivRaw=NULL
namesOnIV=c()
if (length(ivLocalIdx)>0)
{
#analyze all IV definitions
ivRaw=''
for (ivLLidx in 1:length(ivLocalIdx))
{
nextKwIdx=min(kwIdx[which(kwIdx>ivIndexes[ivLocalIdx[ivLLidx]])])
ivRawSingle=paste(cleanModel[ivIndexes[ivLocalIdx[ivLLidx]]:(nextKwIdx-1)],collapse='')
ivRawSingle=gsub("^IV\\s*>", "", ivRawSingle, ignore.case=TRUE)
ivRawSingle=gsub("\\s*", "", ivRawSingle)
ivRaw=paste0(ivRawSingle,';',ivRaw)
}
#analyze ivRaw
ivComponents=strsplit(ivRaw,';')[[1]]
if (length(ivComponents)<1) stop('LOAD_MODEL(): NULL length on IV definition "',ivRaw,' in behavioral "',behavioralName,'".')
for (idxIVComp in 1:length(ivComponents))
{
if (! .checkExpression(ivComponents[idxIVComp]))
stop('LOAD_MODEL(): syntax error in IV definition: "',ivComponents[idxIVComp],'" in behavioral "',behavioralName,'".')
#check unknown funs names
unknownFuns=.unknownFunsNames(ivComponents[idxIVComp],reservedKeyw)
if (length(unknownFuns)>0) stop('LOAD_MODEL(): unsupported functions in IV definition: "',ivComponents[idxIVComp],'" in behavioral "',behavioralName,'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
#trim and extract symbol names from IV
namesOnIV=c(namesOnIV,strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnEqCleaner,' ',ivComponents[idxIVComp],ignore.case=TRUE)),'\\s+')[[1]])
}
#remove numbers from names
rmvNumOnIVIdx=c()
for (idxNamesOnIV in 1:length(namesOnIV)) {
if (length(grep(strongCharOnNumbs,namesOnIV[idxNamesOnIV]))>0)
{
rmvNumOnIVIdx=c(rmvNumOnIVIdx,idxNamesOnIV)
}
}
if (length(rmvNumOnIVIdx)>0) namesOnIV=namesOnIV[-rmvNumOnIVIdx]
#check names
for (idxNOEQ in 1:length(namesOnIV)) {
if (length(grep(allowedCharOnName,namesOnIV[idxNOEQ]))==0)
{
stop('LOAD_MODEL(): syntax error in IV definition: "',ivRaw,'". The following symbol cannot be a variable name: "',namesOnIV[idxNOEQ],'" (behavioral "',behavioralName,'").')
}
if ((grepl('__',namesOnIV[idxNOEQ])))
stop(paste0('LOAD_MODEL(): IV definition "',namesOnIV[idxNOEQ],'" cannot contain double underscore "__" (behavioral "',behavioralName,'").'))
}
}
behavioralTmp$eq=eqRaw
behavioralTmp$iv=ivRaw
behavioralTmp$eqCoefficientsNames=coeff
behavioralTmp$eqCoefficientsCount=length(coeff)
behavioralTmp$eqCoefficientsNamesOriginal=coeffOriginal
behavioralTmp$eqComponentsNames=sort(unique(namesOnEq))
behavioralTmp$IVComponentsNames=sort(unique(namesOnIV))
behavioralTmp$tsrange=behavioralTsrange
behavioralTmp$storeVarName=storeVarName
behavioralTmp$storePosition=storePosition
behavioralTmp$eqRegressorsNames=eqRegressorsNames
behavioralTmp$eqRegressorsNamesOriginal=eqRegressorsNamesOriginal
behavioralTmp$pdlRaw=pdlRaw
behavioralTmp$pdlMatrix=bm_pdlMatrix
behavioralTmp$pdlRestrictionMatrix=bm_pdlRestrictionMatrix
behavioralTmp$pdlRestrictionVector=bm_pdlRestrictionVector
behavioralTmp$restrictRaw=restrictRaw
behavioralTmp$errorRaw=errorRaw
behavioralTmp$errorType=errorType
behavioralTmp$errorDim=errorDim
behavioralTmp$lhsFun=lhsFun
#append to model list of behavioral
if (! is.null(model$behaviorals[[behavioralName]]))
stop('LOAD_MODEL(): duplicated behavioral name "',behavioralName,'".')
model$behaviorals[[behavioralName]]=behavioralTmp
#add name to vendog in related position (required for ordering algo)
#we want the same order in vendog as the one in MDL
model$vendog[behavioralIndexes[idxBI]]=behavioralName
}# end behavioral loop
#analyze code identities ----------------------------------------------------------------------
model$identities=list()
if (length(identityIndexes)>0) for(idxII in 1:length(identityIndexes))
{
identityTmp=list()
#get next keyword definition index
nextKwIdx=min(kwIdx[which(kwIdx>identityIndexes[idxII])])
#read all lines of behavior definition
identitylRaw=paste(cleanModel[identityIndexes[idxII]:(nextKwIdx-1)],collapse=' ')
identitylRaw=gsub("^IDENTITY\\s*>", "", identitylRaw, ignore.case=TRUE)
identitylRaw=gsub("^\\s+|\\s+$", "", identitylRaw)
#get identity name
identityName=gsub("^\\s+|\\s+$", "",identitylRaw)
if (nchar(identityName)==0) stop('LOAD_MODEL(): unknown identity name in line: "',cleanModel[identityIndexes[idxII]],'".')
if (length(grep(allowedCharOnName,identityName))==0) stop('LOAD_MODEL(): invalid identity name: "',identityName,'"')
#get next eq definition index
nextDefIdx=min(eqIdenDefIdx[which(eqIdenDefIdx>identityIndexes[idxII])])
#check identity has eq def
eqLocalIdx=which(eqIndexes %in% identityIndexes[idxII]:(nextDefIdx-1))
if (length(eqLocalIdx)==0) stop('LOAD_MODEL(): no EQ definition in identity "',identityName,'".')
if (length(eqLocalIdx)>1) stop('LOAD_MODEL(): multiple EQ definitions in identity "',identityName,'".')
#get eq
#read all lines of EQ definition
nextKwIdx=min(kwIdx[which(kwIdx>eqIndexes[eqLocalIdx])])
eqRaw=paste(cleanModel[eqIndexes[eqLocalIdx]:(nextKwIdx-1)],collapse=' ')
eqRaw=gsub("^EQ\\s*>", "", eqRaw, ignore.case=TRUE)
eqRaw=gsub("\\s*", "", eqRaw)
#check unknown funs names
unknownFuns=.unknownFunsNames(eqRaw,reservedKeyw)
if (length(unknownFuns)>0) stop('LOAD_MODEL(): unsupported functions in identity "',identityName,'" in EQ definition: "',eqRaw,'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
#check EQ is non trivial
if (nchar(eqRaw)==0 || !grepl('=',eqRaw))
stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in EQ definition: "',eqRaw,'".')
#trim and extract symbol names from EQ
#we keep dependent
namesOnEq=strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnEqCleaner,' ',eqRaw,ignore.case=TRUE)),'\\s+')[[1]]
#check EQ is non trivial
if ( length(namesOnEq)==0 )
stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in EQ definition: "',eqRaw,'".')
eqRawSplitted=strsplit(eqRaw,'\\=')[[1]]
if (length(eqRawSplitted)!=2) stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in EQ definition: "',eqRaw,'".')
#convert RHS text to expression
rhsExp=eqRawSplitted[2]
lhsExp=eqRawSplitted[1]
if (lhsExp=='') stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in EQ definition: "',eqRaw,'".')
#find lhs func
tryCatch({
lhsFun=.parseLhsEQ(lhsExp,allowedLhsEQfuns)
},error=function(err){
stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in LHS of EQ definition: "',eqRaw,'".')})
# lhs identity -------------------------------------------------------------------
#check lhs fun syntax
if (lhsFun$funName=='I')
{
#check EQ contains identity name
if (lhsFun$args!=identityName)
stop('LOAD_MODEL(): LHS of EQ definition: "',eqRaw,'" must contain only the identity name "',identityName,'" or the allowed uppercase LHS functions: ',paste0(paste0(allowedLhsEQfunsPub,'()'),collapse=', '))
if (lhsExp!=paste0(identityName))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',identityName,'" are allowed on the LHS of EQ definition, e.g. EQ> ',identityName,'=...')
} else if (lhsFun$funName=='LOG')
{
if (lhsFun$argsCount!=1 || lhsFun$args!=identityName )
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the identity "',identityName,'". If the LOG of the endogenous variable is requested please try the following: "LOG(',identityName,')"')
if (lhsExp!=paste0('LOG(',identityName,')'))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',identityName,'" are allowed on the LHS of EQ definition, e.g. EQ> LOG(',identityName,')=...')
} else if (lhsFun$funName=='EXP')
{
if (lhsFun$argsCount!=1 || lhsFun$args!=identityName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the identity "',identityName,'". If the EXP of the endogenous variable is requested please try the following: "EXP(',identityName,')"')
if (lhsExp!=paste0('EXP(',identityName,')'))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',identityName,'" are allowed on the LHS of EQ definition, e.g. EQ> EXP(',identityName,')=...')
} else if (lhsFun$funName=='TSDELTA' || lhsFun$funName=='DEL')
{
if ( lhsFun$argsCount>2 || lhsFun$args[1]!=identityName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the identity "',identityName,'". If the TSDELTA of the endogenous variable is requested please try the following: "TSDELTA(',identityName,')" or "TSDELTA(',identityName,',n)"')
if (lhsExp!=paste0(lhsFun$funName,'(',identityName,',',lhsFun$args[2],')') && lhsExp!=paste0(lhsFun$funName,'(',identityName,')'))
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',identityName,'" are allowed on the LHS of EQ definition, e.g. EQ> TSDELTA(',identityName,',n)=...')
} else if (lhsFun$funName=='TSDELTAP' )
{
if ( lhsFun$argsCount>2 || lhsFun$args[1]!=identityName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the identity "',identityName,'". If the TSDELTAP of the endogenous variable is requested please try the following: "TSDELTAP(',identityName,')" or "TSDELTAP(',identityName,',n)"')
if (lhsExp!=paste0(lhsFun$funName,'(',identityName,',',lhsFun$args[2],')') && lhsExp!=paste0(lhsFun$funName,'(',identityName,')') )
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',identityName,'" are allowed on the LHS of EQ definition, e.g. EQ> TSDELTAP(',identityName,',n)=...')
} else if (lhsFun$funName=='TSDELTALOG' )
{
if ( lhsFun$argsCount>2 || lhsFun$args[1]!=identityName)
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'" of the identity "',identityName,'". If the TSDELTALOG of the endogenous variable is requested please try the following: "TSDELTALOG(',identityName,')" or "TSDELTALOG(',identityName,',n)"')
if (lhsExp!=paste0(lhsFun$funName,'(',identityName,',',lhsFun$args[2],')') && lhsExp!=paste0(lhsFun$funName,'(',identityName,')') )
stop('LOAD_MODEL(): syntax error in LHS of EQ definition: "',eqRaw,'". Only the identity function or a single transformation of the endogenous variable "',identityName,'" are allowed on the LHS of EQ definition, e.g. EQ> TSDELTALOG(',identityName,',n)=...')
}
if (! .checkExpression(rhsExp)) stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in RHS of EQ definition: "',eqRaw,'".')
#remove numbers
rmvNumOnEqIdx=c()
for (idxNamesOnEq in 1:length(namesOnEq)) {
if (length(grep(strongCharOnNumbs,namesOnEq[idxNamesOnEq]))>0)
{
rmvNumOnEqIdx=c(rmvNumOnEqIdx,idxNamesOnEq)
}
}
if (length(rmvNumOnEqIdx)>0) namesOnEq=namesOnEq[-rmvNumOnEqIdx]
#check components name
for (idxNOEQ in 1:length(namesOnEq)) {
if (length(grep(allowedCharOnName,namesOnEq[idxNOEQ]))==0)
{
stop('LOAD_MODEL(): syntax error in identity "',identityName,'" in EQ definition: "',eqRaw,'". The following symbol cannot be a variable name: "',namesOnEq[idxNOEQ],'".')
}
}
#check identity has IF def
ifLocalIdx=which(ifIndexes %in% identityIndexes[idxII]:(nextDefIdx-1))
ifRaw=NULL
identityTmp$hasIF=FALSE
if (length(ifLocalIdx)>0)
{
if (length(ifLocalIdx)>1) stop('LOAD_MODEL(): multiple IF definitions in identity "',identityName,'".')
ifRaw=''
nextKwIdx=min(kwIdx[which(kwIdx>ifIndexes[ifLocalIdx])])
ifRaw=paste(cleanModel[ifIndexes[ifLocalIdx]:(nextKwIdx-1)],collapse=' ')
ifRaw=gsub("^IF\\s*>", "", ifRaw, ignore.case=TRUE)
ifRaw=gsub("^\\s*|\\s*$", "", ifRaw)
#check for unknown funs
unknownFuns=.unknownFunsNames(ifRaw,reservedKeyw)
if (length(unknownFuns)>0) stop('LOAD_MODEL(): unsupported functions in IF definition: "',ifRaw,'" in identity "',identityName,'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
#check double logical operator
if (grepl('&&',ifRaw)) stop('LOAD_MODEL(): IF definition: "',ifRaw,'" in identity "',identityName,'" cannot contain "&&". Please consider using the single operator "&"')
if (grepl('\\|\\|',ifRaw)) stop('LOAD_MODEL(): IF definition: "',ifRaw,'" in identity "',identityName,'" cannot contain "||". Please consider using the single operator "|"')
#extract components names from IF
namesOnIf=strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnIfCleaner,' ',ifRaw,ignore.case=TRUE)),'\\s+')[[1]]
#remove numbers
rmvNumOnIfIdx=c()
for (idxNamesOnIf in 1:length(namesOnIf)) {
if (length(grep(strongCharOnNumbs,namesOnIf[idxNamesOnIf]))>0)
{
rmvNumOnIfIdx=c(rmvNumOnIfIdx,idxNamesOnIf)
}
}
if (length(rmvNumOnIfIdx)>0) namesOnIf=namesOnIf[-rmvNumOnIfIdx]
#check IF condition is time series
if (length(namesOnIf)==0) stop(paste0('LOAD_MODEL(): syntax error in IF condition "',ifRaw,'" in identity "',identityName,'". Logical condition must contain time series.'))
#check components name
for (idxNOEQ in 1:length(namesOnIf)) {
if (length(grep(allowedCharOnName,namesOnIf[idxNOEQ]))==0)
{
stop(paste0('LOAD_MODEL(): syntax error in IF definition: "',ifRaw,'" in identity "',identityName,'". The following symbol cannot be a variable name: "',namesOnIf[idxNOEQ],'".'))
}
}
namesOnEq=c(namesOnEq,namesOnIf)
}
#store stuff with trailing ";"
identityTmp$eqRaw=paste0(eqRaw,';')
#we must deal with multiple lhsFun due to IF conditions
#e.g. __IF__ (x<0) __THEN__ EXP(y)=x; __IF__(x>=0) __THEN__ DELTAP(y)=x
#we need a list of lists
identityTmp$multipleLhsFun=list(lhsFun)
#build identity eq as __IF__ (condition) __THEN__ EQ
if (! is.null(ifRaw))
{
tmpIfRaw=ifRaw
tmpIfRaw=gsub('\\.EQ\\.',' == ',tmpIfRaw)
tmpIfRaw=gsub('\\.NE\\.',' != ',tmpIfRaw)
tmpIfRaw=gsub('\\.GE\\.',' >= ',tmpIfRaw)
tmpIfRaw=gsub('\\.LE\\.',' <= ',tmpIfRaw)
tmpIfRaw=gsub('\\.GT\\.',' > ',tmpIfRaw)
tmpIfRaw=gsub('\\.LT\\.',' < ',tmpIfRaw)
tmpIfRaw=gsub('<-','< -',tmpIfRaw)
if (! grepl('(==|<|>|>=|<=|!=|&|\\|)',tmpIfRaw))
stop(paste0('LOAD_MODEL(): syntax error in IF condition "',ifRaw,'" in identity "',identityName,'". No logical operator found.'))
if (! .checkExpression(tmpIfRaw)) stop('LOAD_MODEL(): syntax error in IF definition: "',tmpIfRaw,'" in identity "',identityName,'".')
identityTmp$eqFull=paste0('__IF__ (',ifRaw,') __THEN__ ',identityTmp$eqRaw)
identityTmp$ifCondition=paste0(tmpIfRaw,';')
identityTmp$hasIF=TRUE
}
else
{
identityTmp$ifCondition=paste0('__TRUE__;')
identityTmp$eqFull=identityTmp$eqRaw
}
identityTmp$eqComponentsNames=sort(unique(namesOnEq))
#RAW must be refined
if (! is.null(ifRaw)) identityTmp$ifRaw=paste0(ifRaw,';')
#append to model list of identities.
if (! is.null(model$identities[[identityName]]))
{
#check lhs function is the same for all identity equations in same vendog
baseLhsFun=model$identities[[identityName]]$multipleLhsFun[[1]]
if (baseLhsFun$funName!=lhsFun$funName || any(baseLhsFun$args != lhsFun$args))
{
stop('LOAD_MODEL(): error in identity "',identityName,'", all EQ equations must have the same LHS function.')
}
model$identities[[identityName]]$eqRaw=paste0(model$identities[[identityName]]$eqRaw,identityTmp$eqRaw)
model$identities[[identityName]]$ifCondition=paste0(model$identities[[identityName]]$ifCondition,identityTmp$ifCondition)
model$identities[[identityName]]$multipleLhsFun[length(model$identities[[identityName]]$multipleLhsFun)+1]=
list(lhsFun)
if (! is.null(ifRaw))
{
model$identities[[identityName]]$ifRaw=paste0(model$identities[[identityName]]$ifRaw,identityTmp$ifRaw)
#identity$hasIf == TRUE if any eq has IF condition
model$identities[[identityName]]$hasIF=model$identities[[identityName]]$hasIF || identityTmp$hasIF
}
model$identities[[identityName]]$eqFull=paste0(model$identities[[identityName]]$eqFull,identityTmp$eqFull)
model$identities[[identityName]]$eqComponentsNames=sort(unique(c(model$identities[[identityName]]$eqComponentsNames,identityTmp$eqComponentsNames)))
} else
{
#if new identity has no if than store only latter
model$identities[[identityName]]=identityTmp
#add name to vendog in related position (required for ordering algo)
#we want the same order in vendog as the one in MDL (?)
model$vendog[identityIndexes[idxII]]=identityName
}
}# end identities loop
#store stuff
model$cleanModel=cleanModel
model$rawData=rawData
totNumEqs=length(behavioralIndexes)
totNumIds=length(model$identities) #can have more indexes than identities due to IF
model$totNumEqs=totNumEqs
model$totNumIds=totNumIds
model$eqCoeffNum=totNumCoeff
#set max lag/leead to default
model$max_lag=0
model$max_lead=0
if (totNumEqs+totNumIds==0) stop('LOAD_MODEL(): empty model.')
#remove NAs from vendog (we inserted vars in model$vendog using their line position in model text)
model$vendog=model$vendog[! is.na(model$vendog)]
#create sublists for vendog behaviorals and vendog identities
vendogBehaviorals=base::intersect(model$vendog,names(model$behaviorals))
if (length(vendogBehaviorals)>0)
if (all(nchar(vendogBehaviorals)>0))
model$vendogBehaviorals=vendogBehaviorals
vendogIdentities=base::intersect(model$vendog,names(model$identities))
if (length(vendogIdentities)>0)
if (all(nchar(vendogIdentities)>0))
model$vendogIdentities=vendogIdentities
#create field for exogenous variables
vexog=c()
if (length(model$behaviorals)>0) for (i in 1:length(model$behaviorals))
{
vexog=c(vexog,model$behaviorals[[i]]$eqComponentsNames)
}
if (length(model$identities)>0) for (i in 1:length(model$identities))
{
vexog=c(vexog,model$identities[[i]]$eqComponentsNames)
}
vexog=unique(vexog)
#remove endogenous
rmvIdx=which(vexog %in% model$vendog)
if (length(rmvIdx)>0) vexog=vexog[-rmvIdx]
model$vexog=vexog
#deal with reserved words
allNames=c(model$vendog,model$vexog)
if (any(grepl('__',allNames)))
stop(paste0('LOAD_MODEL(): variable names cannot contain double underscore "__". Please change the following variable names: ',paste0(allNames[which(grepl('__',allNames))],collapse=', ')))
if (length(model$vexog)==0 && (! quietly) ) .MODEL_outputText(outputText=!quietly,'\nLOAD_MODEL(): warning, model has no exogenous variables.\n')
#probably never occur
if (length(model$vendog)==0 && (! quietly) ) .MODEL_outputText(outputText=!quietly,'\nLOAD_MODEL(): warning, model has no endogenous variables.\n')
# behavioral expr and max_lag ----------------------------------
.MODEL_outputText(outputText=!quietly,'Analyzing behaviorals...\n')
#build RHS expressions in behaviorals and identities (needed to speedup simulation...)
#cycle in behaviorals
length_model_behaviorals=length(model$behaviorals)
names_model_behaviorals=names(model$behaviorals)
if (length_model_behaviorals>0) for(idxB in 1:length_model_behaviorals)
{#cycle in components
outRHS=''
currentVendog=names_model_behaviorals[idxB]
currentBehavioral=model$behaviorals[[idxB]]
for (idxC in 1:length(currentBehavioral$eqCoefficientsNames))
{
#build "+COEF*REGR"
outRHS=paste0(outRHS, '+' ,
paste0(currentVendog,'__COEFF__',currentBehavioral$eqCoefficientsNames[idxC]),
'*',
(currentBehavioral$eqRegressorsNames[idxC]))
}
#replace fun names
outRHS=.MODEL_MOD_FUNC_NAMES(outRHS)
#add constant adjustment (outRHS already starts with "+")
outRHS=paste0(currentVendog,'__ADDFACTOR',outRHS)
#adapt eqRHS to autocorrelation if required
if (! is.null(currentBehavioral$errorType) && currentBehavioral$errorType=='AUTO')
{
#add lagged errors to eqRHS, e.g. TSDELTAP(y)-EQ
errorEqRaw=paste0(.MODEL_MOD_FUNC_NAMES(currentBehavioral$lhsFun$raw),'-(',outRHS,')')
for (idxED in 1:currentBehavioral$errorDim)
{
#final RHS EQ is original one plus lagged errors
#warning: in DYNAMIC simulation RHO*LAG(y-f(x)) is always 0
#if simulation period > errorDim
outRHS=paste0(outRHS,'+',currentVendog,'__RHO__',idxED,'*.MODEL_TSLAG(',errorEqRaw,',',idxED,')')
}
}
localComponentsNames=currentBehavioral$eqComponentsNames
#create local sublist for behaviorals and identities components
localComponentsNamesBehaviorals=base::intersect(model$vendogBehaviorals,localComponentsNames)
if (length(localComponentsNamesBehaviorals)>0)
if (all(nchar(localComponentsNamesBehaviorals)>0))
currentBehavioral$eqComponentsNamesBehaviorals=localComponentsNamesBehaviorals
localComponentsNamesIdentities=base::intersect(model$vendogIdentities,localComponentsNames)
if (length(localComponentsNamesIdentities)>0)
if (all(nchar(localComponentsNamesIdentities)>0))
currentBehavioral$eqComponentsNamesIdentities=localComponentsNamesIdentities
localComponentsNamesExogenous=base::intersect(model$vexog,localComponentsNames)
if (length(localComponentsNamesExogenous)>0)
if (all(nchar(localComponentsNamesExogenous)>0))
currentBehavioral$eqComponentsNamesExogenous=localComponentsNamesExogenous
tryCatch({
outSim=''
if(currentBehavioral$lhsFun$funName=='I')
{
#build outSim
outSim=paste0(currentVendog,'=',outRHS)
} else if (currentBehavioral$lhsFun$funName=='LOG')
{
outSim=paste0(currentVendog,'=exp(',outRHS,')')
} else if (currentBehavioral$lhsFun$funName=='EXP')
{
outSim=paste0(currentVendog,'=log(',outRHS,')')
} else if (currentBehavioral$lhsFun$funName=='TSDELTA' || currentBehavioral$lhsFun$funName=='DEL')
{
if (currentBehavioral$lhsFun$argsCount>1 && ! is.finite(as.numeric(currentBehavioral$lhsFun$args[2])))
stop('Non-numeric lag in LHS function: TSDELTA()')
if (currentBehavioral$lhsFun$argsCount>1) tmpS=currentBehavioral$lhsFun$args[2]
else tmpS='1'
outSim=paste0(currentVendog,'=',outRHS,'+.MODEL_TSLAG(',currentVendog,',',tmpS,')')
} else if (currentBehavioral$lhsFun$funName=='TSDELTAP' )
{
if (currentBehavioral$lhsFun$argsCount>1 && ! is.finite(as.numeric(currentBehavioral$lhsFun$args[2])))
stop('Non-numeric lag in LHS function: TSDELTAP()')
if (currentBehavioral$lhsFun$argsCount>1) tmpS=currentBehavioral$lhsFun$args[2]
else tmpS='1'
outSim=paste0(currentVendog,'=(',outRHS,
')*.MODEL_TSLAG(',currentVendog,',',tmpS,')/100',
'+.MODEL_TSLAG(',currentVendog,',',tmpS,')')
} else if (currentBehavioral$lhsFun$funName=='TSDELTALOG' )
{
if (currentBehavioral$lhsFun$argsCount>1 && ! is.finite(as.numeric(currentBehavioral$lhsFun$args[2])))
stop('Non-numeric lag in LHS function: TSDELTALOG()')
if (currentBehavioral$lhsFun$argsCount>1) tmpS=currentBehavioral$lhsFun$args[2]
else tmpS='1'
outSim=paste0(currentVendog,'=exp(',outRHS,
')*.MODEL_TSLAG(',currentVendog,',',tmpS,')')
}
#add indexes to vars
outSim=.appendIndexToVars(outSim,c(localComponentsNames,
paste0(currentVendog,'__ADDFACTOR'))
,'0')
#explode model funs
tempS=.explodeTSLAG(outSim)
tempS=.explodeTSLEAD(tempS$output)
tempS=.explodeTSDELTA(tempS$output)
tempS=.explodeTSDELTAP(tempS$output)
tempS=.explodeTSDELTALOG(tempS$output)
tempS=.explodeMTOT(tempS$output)
tempS=.explodeMAVE(tempS$output)
outSim=tempS$output
#get max lag lead
tempOut=.getLowerLagAndHigherLead(outSim)
model$max_lag=max(model$max_lag,-tempOut$outL)
model$max_lead=max(model$max_lead,tempOut$outH)
#save sim expression
currentBehavioral$eqSimExpText=outSim
},error=function(e){stop(paste0('LOAD_MODEL(): error in behavioral "',
currentVendog,'" while parsing EQ expression "',currentBehavioral$eq,'". ',e$message))})
#store stuff
model$behaviorals[[idxB]]=currentBehavioral
}
# identity expr and max lag ----------------------------------
.MODEL_outputText(outputText=!quietly,'Analyzing identities...\n')
#cycle in identities
length_model_identities=length(model$identities)
names_model_identities=names(model$identities)
if (length_model_identities>0) for(idxI in 1:length_model_identities)
{
currentIdentity=model$identities[[idxI]]
currentVendog=names_model_identities[idxI]
localComponentsNames=currentIdentity$eqComponentsNames
#create local sublist for behaviorals and identities components
localComponentsNamesBehaviorals=base::intersect(model$vendogBehaviorals,localComponentsNames)
if (length(localComponentsNamesBehaviorals)>0)
if (all(nchar(localComponentsNamesBehaviorals)>0))
currentIdentity$eqComponentsNamesBehaviorals=localComponentsNamesBehaviorals
localComponentsNamesIdentities=base::intersect(model$vendogIdentities,localComponentsNames)
if (length(localComponentsNamesIdentities)>0)
if (all(nchar(localComponentsNamesIdentities)>0))
currentIdentity$eqComponentsNamesIdentities=localComponentsNamesIdentities
localComponentsNamesExogenous=base::intersect(model$vexog,localComponentsNames)
if (length(localComponentsNamesExogenous)>0)
if (all(nchar(localComponentsNamesExogenous)>0))
currentIdentity$eqComponentsNamesExogenous=localComponentsNamesExogenous
#get identities multiple eqs and conditions
eqRawSplitted=strsplit(currentIdentity$eqRaw,';')[[1]]
ifConditionSplitted=strsplit(currentIdentity$ifCondition,';')[[1]]
if (length(eqRawSplitted)!=length(ifConditionSplitted))
stop(paste0('LOAD_MODEL(): equations EQ count differs from logical IF condition count in identity "',currentVendog,'".'))
if (length(eqRawSplitted)!=length(currentIdentity$multipleLhsFun))
stop(paste0('LOAD_MODEL(): equations EQ count differs from LHS functions count in identity "',currentVendog,'".'))
outSim=''
#cycle in eq
for (eqIdx in 1:length(eqRawSplitted))
{
tryCatch({
#get single eq and if condition in identity
eqRaw=eqRawSplitted[eqIdx]
ifConditionRaw=ifConditionSplitted[eqIdx]
RHSRawComponent=strsplit(eqRaw,'=')[[1]][2]
if (ifConditionRaw=='__TRUE__')
{
ifRawComponent='TRUE'
} else
{
ifRawComponent=ifConditionRaw
}
#parse expression
ifModText=.MODEL_MOD_FUNC_NAMES(ifRawComponent)
RHSmodeText=.MODEL_MOD_FUNC_NAMES(RHSRawComponent)
#add add-factor
RHSmodeText=paste0(currentVendog,'__ADDFACTOR+',RHSmodeText)
if (currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'I')
{
#nop
} else if (currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'LOG')
{
RHSmodeText=paste0('exp(',RHSmodeText,')')
} else if (currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'EXP')
{
RHSmodeText=paste0('log(',RHSmodeText,')')
} else if (currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'TSDELTA' || currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'DEL')
{
if (currentIdentity$multipleLhsFun[[eqIdx]]$argsCount>1 && ! is.finite(as.numeric(currentIdentity$multipleLhsFun[[eqIdx]]$args[2])))
stop('Non-numeric lag in LHS function: TSDELTA()')
if (currentIdentity$multipleLhsFun[[eqIdx]]$argsCount>1) tmpS=currentIdentity$multipleLhsFun[[eqIdx]]$args[2]
else tmpS='1'
RHSmodeText=paste0(RHSmodeText,'+.MODEL_TSLAG(',currentVendog,',',tmpS,')')
} else if (currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'TSDELTAP' )
{
if (currentIdentity$multipleLhsFun[[eqIdx]]$argsCount>1 && ! is.finite(as.numeric(currentIdentity$multipleLhsFun[[eqIdx]]$args[2])))
stop('Non-numeric lag in LHS function: TSDELTAP()')
if (currentIdentity$multipleLhsFun[[eqIdx]]$argsCount>1) tmpS=currentIdentity$multipleLhsFun[[eqIdx]]$args[2]
else tmpS='1'
RHSmodeText=paste0('(',RHSmodeText,
')*.MODEL_TSLAG(',currentVendog,',',tmpS,')/100',
'+.MODEL_TSLAG(',currentVendog,',', tmpS,')')
} else if (currentIdentity$multipleLhsFun[[eqIdx]]$funName == 'TSDELTALOG' )
{
if (currentIdentity$multipleLhsFun[[eqIdx]]$argsCount>1 && ! is.finite(as.numeric(currentIdentity$multipleLhsFun[[eqIdx]]$args[2])))
stop('Non-numeric lag in LHS function: TSDELTALOG()')
if (currentIdentity$multipleLhsFun[[eqIdx]]$argsCount>1) tmpS=currentIdentity$multipleLhsFun[[eqIdx]]$args[2]
else tmpS='1'
RHSmodeText=paste0('exp(',RHSmodeText,
')*.MODEL_TSLAG(',currentVendog,',',tmpS,')')
}
if (ifRawComponent=='TRUE') tmpS=paste0(currentVendog,'=',RHSmodeText,';')
else tmpS=paste0(currentVendog,'=.MODEL_VIF(',currentVendog,
',',ifModText,',',RHSmodeText,');')
#build sim expresion w. constant adjustment
outSim=paste0(outSim,tmpS)
},error=function(e){
stop(paste0('LOAD_MODEL(): error parsing EQ expression "',eqRaw,'" in identity "',currentVendog, '" - ', e$message))
})
}
tryCatch({
#add indexes to vars
outSim=.appendIndexToVars(outSim,c(localComponentsNames,
paste0(currentVendog,'__ADDFACTOR'))
,'0')
#explode model funs
tempS=.explodeTSLAG(outSim)
tempS=.explodeTSLEAD(tempS$output)
tempS=.explodeTSDELTA(tempS$output)
tempS=.explodeTSDELTAP(tempS$output)
tempS=.explodeTSDELTALOG(tempS$output)
tempS=.explodeMTOT(tempS$output)
tempS=.explodeMAVE(tempS$output)
outSim=tempS$output
currentIdentity$eqSimExpText=outSim
#get max lag lead
tempOut=.getLowerLagAndHigherLead(outSim)
model$max_lag=max(model$max_lag,-tempOut$outL)
model$max_lead=max(model$max_lead,tempOut$outH)
},error=function(e){stop(paste0('LOAD_MODEL(): error while building simulation expression of identity ',
currentVendog,'. ',e$message))})
#update identity
model$identities[[idxI]]=currentIdentity
}#end loop identities
# reordering incidence ------------------------
#backward looking model
if (model$max_lead==0)
{
.MODEL_outputText(outputText=!quietly,'Optimizing...\n')
#build incidence matrix
incidence_matrix=matrix(0,nrow=length(model$vendog), ncol=length(model$vendog))
colnames(incidence_matrix)=model$vendog
rownames(incidence_matrix)=model$vendog
if (length_model_behaviorals>0) for(idxB in 1:length_model_behaviorals)
{
currentVendog=names_model_behaviorals[idxB]
currentBehavioral=model$behaviorals[[idxB]]
tryCatch({
#get incidence matrix row
vendogComponents=c(currentBehavioral$eqComponentsNamesBehaviorals,currentBehavioral$eqComponentsNamesIdentities)
outSim=currentBehavioral$eqSimExpText
incidenceVendogs=.getIncidenceVendogs(currentVendog,outSim,
vendogComponents)
#save stuff
if (length(incidenceVendogs)>0)
for (idxIV in 1:length(incidenceVendogs))
incidence_matrix[currentVendog,
incidenceVendogs[idxIV]]=1
},error=function(e){stop(paste0('LOAD_MODEL(): error while building incidence row for behavioral ',
currentVendog,'. ',e$message))})
}
if (length_model_identities>0) for(idxI in 1:length_model_identities)
{
currentIdentity=model$identities[[idxI]]
currentVendog=names_model_identities[idxI]
tryCatch({
#get incidence matrix
vendogComponents=c(currentIdentity$eqComponentsNamesBehaviorals,currentIdentity$eqComponentsNamesIdentities)
outSim=currentIdentity$eqSimExpText
incidenceVendogs=.getIncidenceVendogs(currentVendog,outSim,
vendogComponents)
#save stuff
if (length(incidenceVendogs)>0)
for (idxIV in 1:length(incidenceVendogs))
incidence_matrix[currentVendog,
incidenceVendogs[idxIV]]=1
},error=function(e){stop(paste0('LOAD_MODEL(): error while building incidence vector of identity ',
currentVendog,'. ',e$message))})
}
#export incidence matrix
model$incidence_matrix=incidence_matrix
#create vblocks
modelBlocks=.buildBlocks(incidence_matrix)
model$vblocks=modelBlocks$vblocks
model$vpre=modelBlocks$vpre
varsCount=length(model$vpre)
if (length(model$vblocks)>0)
for (idxB in 1:length(model$vblocks)) varsCount=varsCount+
length(model$vblocks[[idxB]]$vsim)+
length(model$vblocks[[idxB]]$vpost)
if (varsCount != length(model$vendog))
stop('LOAD_MODEL(): unknown error while optimizing model. Countings do not match.')
} else {
.MODEL_outputText(outputText=!quietly,'This is a forward looking model...\n')
}
# build sim expressions ----------------------------------------------
#we need at least 2 rows in sim matrices in case of simType='FORECAST'
max_lag_sim_1=max(model$max_lag,1)+1
tryCatch({
if (length(model$behaviorals)>0) for(idxB in 1:length(model$behaviorals))
{
#eqSimExpText must be kept original (i.e. no __LEAD__ tx) because it is needed to
#create leaded expressions
#base sim equation as text, used only to lead base eq in leaded model
model$behaviorals[[idxB]]$eqSimExpText=.addToIndexInString(model$behaviorals[[idxB]]$eqSimExpText,
max_lag_sim_1)
#base sim equation with lead tx as text
#we need eqSimExpLeadedText also in non-leaded models
#because users can simulate with forceForwardLooking=TRUE
model$behaviorals[[idxB]]$eqSimExpLeadedText=.addToIndexInString(model$behaviorals[[idxB]]$eqSimExpText,
0,
TRUE,
max_lag_sim_1)
#parsed base sim eq with lead tx
model$behaviorals[[idxB]]$eqSimExp=parse(text=model$behaviorals[[idxB]]$eqSimExpLeadedText)
}
},error=function(err){stop(paste0('LOAD_MODEL(): error while building sim expression in behavioral "',names(model$behaviorals)[idxB],'". ',err$message))})
tryCatch({
if (length(model$identities)>0) for(idxI in 1:length(model$identities))
{
#eqSimExpText must be kept original (i.e. no __LEAD__ tx) because it is needed to
#create leaded expressions
#base sim equation as text, used only to lead base eq in leaded model
model$identities[[idxI]]$eqSimExpText=.addToIndexInString(model$identities[[idxI]]$eqSimExpText,
max_lag_sim_1)
#base sim equation with lead tx as text
#we need eqSimExpLeadedText also in non-leaded models
#because users can simulate with forceForwardLooking=TRUE
model$identities[[idxI]]$eqSimExpLeadedText=.addToIndexInString(model$identities[[idxI]]$eqSimExpText,
0,
TRUE,
max_lag_sim_1)
#parsed base sim eq with lead tx
model$identities[[idxI]]$eqSimExp=parse(text=model$identities[[idxI]]$eqSimExpLeadedText)
}
},error=function(err){stop(paste0('LOAD_MODEL(): error while building sim expression in identity "',names(model$identities)[idxI],'". ',err$message))})
.MODEL_outputText(outputText=!quietly,'Loaded model "',modelName,'":\n',
sprintf("%5i",model$totNumEqs),' behaviorals\n',
sprintf("%5i",model$totNumIds),' identities\n',
sprintf("%5i",model$eqCoeffNum),' coefficients\n',sep='')
model$modelName=modelName
#set model version
model$bimets_version=getOption('BIMETS_VERSION')
.MODEL_outputText(outputText=!quietly,'...LOAD MODEL OK\n')
return(model)
}
# LOAD MODEL DATA code ---------------------------------------------------------
LOAD_MODEL_DATA <- function(model=NULL,
modelData=NULL,
quietly=FALSE,
...)
{
#check args
if (is.null(model)) stop('LOAD_MODEL_DATA(): NULL model argument.')
if (!(inherits( model ,'BIMETS_MODEL')) ) stop('LOAD_MODEL_DATA(): model must be instance of BIMETS_MODEL class.')
.checkModelBimetsVersion(model, 'LOAD_MODEL_DATA')
#check arg
if (!(is.logical(quietly))) stop('LOAD_MODEL_DATA(): "quietly" must be TRUE or FALSE.')
.MODEL_outputText(outputText=!quietly,paste0('Load model data "',substitute(modelData),'" into model "', model$modelName,'"...\n'))
#copy list to model
model$modelData=modelData
tryCatch({
.CHECK_MODEL_DATA(model,showWarnings=(! quietly),'LOAD_MODEL_DATA(): ')
},error=function(e){stop('LOAD_MODEL_DATA(): ',e$message)})
#add frequency info
model$frequency=frequency(model$modelData[[1]])
.MODEL_outputText(outputText=!quietly,'...LOAD MODEL DATA OK\n')
return(model)
}
# .CHECK MODEL_DATA code -------------------------------------------------------
.CHECK_MODEL_DATA <- function(model=NULL,showWarnings=TRUE,caller='.CHECK_MODEL_DATA(): ',...)
{
if (is.null(model)) stop(caller,'NULL model argument.')
if (!(inherits( model ,'BIMETS_MODEL'))) stop(caller,'model must be instance of BIMETS_MODEL class.')
if (is.null(model$vendog)) stop(caller,'list of endogenous variables not found.')
if (is.null(model$vexog)) stop(caller,'list of exogenous variables not found.')
if (is.null(model$modelData)) stop(caller,'model has no data. Please use LOAD_MODEL_DATA().')
modelData=model$modelData
if (! is.list(modelData)) stop(caller,'modelData must be a list of BIMETS time series.')
if (length(modelData)==0) stop(caller,'empty modelData list.')
if (is.null(names(modelData))) stop(caller,'names of modelData list are NULL.')
if (any(names(modelData)=='')) stop(caller,'there are NULL names in modelData list.')
#check time series
for (idx in 1:length(model$modelData))
{
if (! is.bimets(model$modelData[[idx]]))
stop(caller,'modelData must be a list of BIMETS time series: "',names(model$modelData)[idx],'" time series is not compliant.')
if (frequency(model$modelData[[idx]])!=frequency(model$modelData[[1]]))
stop(caller,'time series must have the same frequency. Check time series "',names(model$modelData)[idx],'"')
if (showWarnings && any(! is.finite(coredata(model$modelData[[idx]]))))
.MODEL_outputText(outputText=showWarnings,paste0(caller,'warning, there are non-finite values in time series "',names(model$modelData)[idx],'".\n',sep=''))
}
return(TRUE)
}
# ESTIMATE code ----------------------------------------------------------------
ESTIMATE <- function(model=NULL,
eqList=NULL,
TSRANGE=NULL,
forceTSRANGE=FALSE,
estTech='OLS',
IV=NULL,
forceIV=FALSE,
quietly=FALSE,
tol=1e-28,
digits=getOption('digits'),
centerCOV=TRUE,
CHOWTEST=FALSE,
CHOWPAR=NULL,
avoidCompliance=FALSE,
...)
{
if (is.null(model) ) stop('ESTIMATE(): NULL model.')
if (!(inherits( model ,'BIMETS_MODEL'))) stop('ESTIMATE(): model must be instance of BIMETS_MODEL class.')
.checkModelBimetsVersion(model, 'ESTIMATE')
if (is.null(estTech) || ((estTech!='OLS') && (estTech!='IV'))) stop('ESTIMATE(): estimation technique not supported.')
if (! is.finite(tol) || tol<=0) stop('ESTIMATE(): please provide a valid tolerance value.')
if ((! is.finite(digits) )|| (digits %% 1 !=0) || digits<=0 || digits > 22)
stop('ESTIMATE(): digits must be an integer between 1 and 16.')
if (!(is.logical(centerCOV)) || is.na(centerCOV)) stop('ESTIMATE(): "centerCOV" must be TRUE or FALSE.')
if (!(is.logical(quietly)) || is.na(quietly)) stop('ESTIMATE(): "quietly" must be TRUE or FALSE.')
if (!(is.logical(forceTSRANGE)) || is.na(forceTSRANGE)) stop('ESTIMATE(): "forceTSRANGE" must be TRUE or FALSE.')
if (!(is.logical(forceIV)) || is.na(forceTSRANGE)) stop('ESTIMATE(): "forceIV" must be TRUE or FALSE.')
if ((! is.logical(CHOWTEST)) || is.na(CHOWTEST)) stop('ESTIMATE(): "CHOWTEST" must be TRUE or FALSE.')
if (is.null(model$modelData) ) stop('ESTIMATE(): model has no data. Please reload model data.')
if (is.null(model$frequency) ) stop('ESTIMATE(): model has no frequency. Please reload model data.')
if (CHOWTEST==TRUE)
{
if (! is.null(CHOWPAR) )
tryCatch({
CHOWPAR=normalizeYP(CHOWPAR,f=model$frequency)
},error=function(e){
stop('ESTIMATE(): please provide "CHOWPAR" as a c(year,period) array.')
})
}
#flag for messages vertbosity
outputText=!quietly
#get regex definitions
regExDefs=.RegExGlobalDefinition()
reservedKeyw=regExDefs$reservedKeyw
symOnEqCleaner=regExDefs$symOnEqCleaner
allowedCharOnName=regExDefs$allowedCharOnName
allowedCharOnNameToken=regExDefs$allowedCharOnNameToken
charsOnNumbs=regExDefs$charsOnNumbs
charsOnNumWithSign=regExDefs$charsOnNumWithSign
strongCharOnNumbs=regExDefs$strongCharOnNumbs
strongCharOnNumbsWithSign=regExDefs$strongCharOnNumbsWithSign
#a new local environment is created in order to improve performance
#it will contains model time series, coefficients, parameters, etc.
#model equations are faster if executed in a isolated environment
#in localE parameters, coefficient, etc. names must contains
#double underscore in order to avoid collisions with model variable names
localE=new.env()
if (! avoidCompliance)
{
tryCatch({
.CHECK_MODEL_DATA(model,showWarnings=(! quietly),'ESTIMATE(): ')
},error=function(e){stop('ESTIMATE(): ',e$message)})
}
#check requested eq names are in model behavioral names
if (! is.null(eqList))
{
for ( eqReqName in eqList)
{
if (! (eqReqName %in% names(model$behaviorals)))
stop('ESTIMATE(): requested equation "',eqReqName,'" is not in model behaviorals list.')
}
} else
{
eqList=names(model$behaviorals)
}
if (length(eqList)==0)
{
.MODEL_outputText(outputText=!quietly,('ESTIMATE(): no behavioral equations to be estimated. Estimation will exit.\n'))
return(model)
}
.MODEL_outputText(outputText=!quietly,'\nEstimate the Model ',model$modelName,':\n',sep='')
.MODEL_outputText(outputText=!quietly,'the number of behavioral equations to be estimated is ',length(eqList),'.\n',sep='')
# num of total coeffs
totCoeff=0
for (eqIdx in 1:length(eqList))
{
totCoeff=totCoeff+length(model$behaviorals[[eqList[eqIdx]]]$eqCoefficientsNames)
}
.MODEL_outputText(outputText=!quietly,'The total number of coefficients is ',totCoeff,'.\n',sep='')
#model data frequecy
frequency=model$frequency
# main loop -----------------------------------------------
for (eqIdx in 1:length(eqList))
{
#proxy current behavioral
currentBehavioral=model$behaviorals[[eqList[eqIdx]]]
#deal with IV
IVlist=list()
#check args
if (estTech=='IV' && is.null(IV) && is.null(currentBehavioral$iv)) stop('ESTIMATE(): please provide instrumental variables "IV".')
if (estTech=='IV' && is.null(IV) && forceIV==TRUE) stop('ESTIMATE(): please provide instrumental variables "IV". "forceIV" is TRUE.')
if (! is.null(IV))
{
if (length(IV)==0) stop('ESTIMATE(): syntax error in "IV".')
for (idxIV in 1:length(IV))
if (! .checkExpression(IV[idxIV]))
stop('ESTIMATE(): syntax error in "IV".')
}
if (!forceIV && !is.null(currentBehavioral$iv))
{
#split iv from MDL
IV=strsplit(currentBehavioral$iv,';')[[1]]
}
if (! is.null(IV))
{
namesOnIV=c()
#trim and check size
for (idxIV in 1:length(IV))
{
#trim leading/trailing spaces
IV[idxIV]=gsub("\\s*", "", IV[idxIV])
#check unknown funs names
unknownFuns=.unknownFunsNames(IV[idxIV],reservedKeyw)
if (length(unknownFuns)>0) stop('ESTIAMTE(): unsupported functions in IV definition: "',IV[idxIV],'" in behavioral "',eqList[eqIdx],'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
if (min(nchar(IV[idxIV]))==0) stop(paste0('ESTIMATE(): misspecified IV element #'),idxIV,' in behavioral "',eqList[eqIdx],'"')
namesOnIV=c(namesOnIV,strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnEqCleaner,' ',IV[idxIV],ignore.case=TRUE)),'\\s+')[[1]])
}
#remove numbers from names
rmvNumOnIVIdx=c()
for (idxNamesOnEq in 1:length(namesOnIV)) {
if (length(grep(strongCharOnNumbs,namesOnIV[idxNamesOnEq]))>0)
{
rmvNumOnIVIdx=c(rmvNumOnIVIdx,idxNamesOnEq)
}
}
if (length(rmvNumOnIVIdx)>0) namesOnIV=namesOnIV[-rmvNumOnIVIdx]
namesOnIV=sort(unique(namesOnIV))
#create local proxies for all references (components names used in eq) in IV
for (idxName in 1:length(namesOnIV))
{
tryCatch(
{
tempName=namesOnIV[idxName]
if (is.null(model$modelData[[tempName]])) stop()
localE[[tempName]]=model$modelData[[tempName]]
},error=function(e){
stop('ESTIMATE(): modelData must contain instrumental variable time series "',tempName,'".',' (behavioral "',eqList[eqIdx],'")')
})
}
#eval expression IV[idx]
for (idxIV in 1:length(IV))
{
tryCatch(
{
#fix funs names
tempName=.MODEL_MOD_FUNC_NAMES(IV[idxIV])
#eval IV expr
tmpIV=eval(parse(text=tempName)
,envir=localE
)
#assign to output list
IVlist[[idxIV]]=tmpIV
},error=function(e){
stop(paste0('ESTIMATE(): cannot evaluate instrumental variable expression "',IV[idxIV],'": ',e$message))
})
}
}# IV exists
statsOut=NULL
#P matrix and options in Cochrane Orcutt (must be defined even if no Cochrane nedeed)
bm_resP=NULL
bm_COmaxIters=1 #CO max iterations
bm_COconvergence=0.005 #CO convergence
bm_COcurrentIter=0 #CO current iteration
bm_COprevRho=NULL #CO previous rho values
.MODEL_outputText(outputText=outputText,'\n_________________________________________\n',sep='')
.MODEL_outputText(outputText=outputText,'\nBEHAVIORAL EQUATION: ',eqList[eqIdx],'\n',sep='')
.MODEL_outputText(outputText=outputText,'Estimation Technique: ',estTech,'\n',sep='')
#number of current behavioral coefficients
bm_coeffNum=length(currentBehavioral$eqCoefficientsNames)
#deal with PDL
thereArePDL=FALSE
bm_pdlMatrix=NULL
if (!(is.null(currentBehavioral$pdlMatrix) ||
is.null(currentBehavioral$pdlRaw) ))
{
thereArePDL=TRUE
bm_pdlMatrix=currentBehavioral$pdlMatrix
bm_pdlRestrictionMatrix=currentBehavioral$pdlRestrictionMatrix
bm_pdlRestrictionVector=currentBehavioral$pdlRestrictionVector
}
#deal with error autocorrelation
thereAreErrorCorr=FALSE
bm_errorType=NULL
bm_errorDim=0
if (!(is.null(currentBehavioral$errorRaw) ||
is.null(currentBehavioral$errorType) ||
is.null(currentBehavioral$errorDim) ))
{
thereAreErrorCorr=TRUE
bm_errorType=currentBehavioral$errorType
bm_errorDim=currentBehavioral$errorDim
bm_errorRaw=currentBehavioral$errorRaw
bm_COmaxIters=20
}
if (thereAreErrorCorr==TRUE)
{
.MODEL_outputText(outputText=outputText,'Autoregression of Order ',bm_errorDim,' (Cochrane-Orcutt procedure)\n')
}
#current behavioral TSRANGE
localTSRANGE=NULL
localTSRANGE_bk=NULL #this is needed if error autocorrelation is required
bm_vectorY_bk=NULL
bm_matrixX_bk=NULL
#behavioral has TSRANGE
if (!forceTSRANGE && all(is.finite(currentBehavioral$tsrange)))
{
localTSRANGE=currentBehavioral$tsrange
} else
{
#check if TSRANGE function argument is compliant
if (! is.null(TSRANGE)) {
tryCatch({
if (! ( is.numeric(TSRANGE) && length(TSRANGE)==4 &&
.isCompliantYP(c(TSRANGE[1],TSRANGE[2]),frequency) &&
.isCompliantYP(c(TSRANGE[3],TSRANGE[4]),frequency) &&
NUMPERIOD(c(TSRANGE[1],TSRANGE[2]),c(TSRANGE[3],TSRANGE[4]),frequency)>=0)
) stop()
},error=function(e) {stop('ESTIMATE(): syntax error in TSRANGE: ',e$message)})
localTSRANGE=TSRANGE
} else
{
stop('ESTIMATE(): neither a local TSRANGE in the behavioral "',eqList[eqIdx],'" MDL nor a global one defined.')
}
}
#build main X matrix: y = X * b + u
bm_matrixX=c()
localTSRANGE_bk=localTSRANGE
if (thereAreErrorCorr==TRUE)
{
#extend tsrange errorDim obs in the past. Cochrane-Orcutt procedure iteration 1
tmpTSR=normalizeYP(c(localTSRANGE[1],localTSRANGE[2]-bm_errorDim),frequency)
localTSRANGE[1]=tmpTSR[1]
localTSRANGE[2]=tmpTSR[2]
}
#check tsrange consistence
tryCatch({
if (NUMPERIOD(c(localTSRANGE[1],localTSRANGE[2]),c(localTSRANGE[3],localTSRANGE[4]),frequency)<0) stop()
},error=function(e){stop('ESTIMATE(): uncompliant TSRANGE in behavioral "',eqList[eqIdx],'"')})
#create local proxies for all references (components names used in eq) in current behavior
for (idxName in 1:length(currentBehavioral$eqComponentsNames))
{
tryCatch(
{
tempName=currentBehavioral$eqComponentsNames[idxName]
if (is.null(model$modelData[[tempName]])) stop()
localE[[tempName]]=model$modelData[[tempName]]
},error=function(e){
stop('ESTIMATE(): modelData must contain time series "',currentBehavioral$eqComponentsNames[idxName],'"')
})
}
#do we have a constant term in regression?
bm_ConstTermExist=FALSE
#used to check regressors have the same length
regressorLengthTest=NULL
#evaluate regressors: min 2
if (length(currentBehavioral$eqRegressorsNames)<1)
stop('ESTIMATE(): behavioral "',eqList[eqIdx],'" has no regressors.')
# regressor eval -----------------------------
#cycle in regressors (#1 is eq name)
regressorLengthTest=1+NUMPERIOD(c(localTSRANGE[1],localTSRANGE[2]),c(localTSRANGE[3],localTSRANGE[4]),frequency)
#build matrix Z if IV
bm_matrixZ=matrix(ncol=length(IVlist),nrow=regressorLengthTest)
if (! is.null(IV))
{
#check IV count is non singular
if (length(IVlist) < length(currentBehavioral$eqCoefficientsNames))
.MODEL_outputText(outputText=!quietly,paste0('\nESTIMATE(): warning, instrumental variables count is less than total regressors count. System may become singular.',
ifelse(thereArePDL,' Please consider also PDL expansion.',''),'\n'))
#project IV into TSRANGE
tryCatch({
for (idxIV in 1:length(IVlist))
{
if ((! is.ts(IVlist[[idxIV]])) && (! is.xts(IVlist[[idxIV]])) )
{
tempRegressor=rep(IVlist[[idxIV]],regressorLengthTest)
} else tempRegressor=(TSPROJECT(IVlist[[idxIV]],ARRAY=TRUE,TSRANGE=localTSRANGE,avoidCompliance=TRUE))
#check regressor size
if (length(tempRegressor)!=regressorLengthTest) stop()
if (any(! is.finite(tempRegressor))) stop()
#assign to matrix
bm_matrixZ[,idxIV]=tempRegressor
}
},error=function(e)
{
stop('ESTIMATE(): instrumental variable expression "',IV[idxIV],
'" in behavioral "',
eqList[eqIdx],'"\n is not defined over the entire TSRANGE ',paste0(localTSRANGE,collapse=','),': ',e$message)
})
} #now we have Z matrix
for (idxRegrs in 1:length(currentBehavioral$eqRegressorsNames))
{
#replace numerical component with columns of numbers (constant term)
if(grepl(strongCharOnNumbs,currentBehavioral$eqRegressorsNames[idxRegrs]))
{
tempRegressorExpr=currentBehavioral$eqRegressorsNames[idxRegrs]
#evaluate expression (regressors definition e.g. 1)
tryCatch({
tempRegressor=eval(parse(text=tempRegressorExpr)
,envir=localE)
},error=function(e)
{
stop('ESTIMATE(): cannot evaluate expression "',currentBehavioral$eqRegressorsNames[idxRegrs],
'"\n(regressor #',idxRegrs,ifelse(thereArePDL,' with PDL expansion',''),') in behavioral "',
eqList[eqIdx],'": ',e$message)})
tempRegressor=rep(tempRegressor,regressorLengthTest)
bm_ConstTermExist=TRUE
} else {
#fix functions names (e.g. LAG -> TSLAG)
tempRegressorExpr=.MODEL_MOD_FUNC_NAMES(currentBehavioral$eqRegressorsNames[idxRegrs])
#evaluate expression (regressors definition e.g. LAG(GDP,3))
tryCatch({
tempRegressor=eval(parse(text=tempRegressorExpr)
,envir=localE)
},error=function(e)
{
stop('ESTIMATE(): cannot evaluate expression "',currentBehavioral$eqRegressorsNames[idxRegrs],
'"\n(regressor #',idxRegrs,ifelse(thereArePDL,' with PDL expansion',''),') in behavioral "',
eqList[eqIdx],'": ',e$message)})
#project regressor on tsrange
tryCatch({
tempRegressor=(TSPROJECT(tempRegressor,TSRANGE=localTSRANGE,ARRAY=TRUE,avoidCompliance=TRUE))
#check regressor size
if (length(tempRegressor)!=regressorLengthTest) stop()
},error=function(e)
{
stop('ESTIMATE(): expression "',currentBehavioral$eqRegressorsNames[idxRegrs],
'"\n(regressor #',idxRegrs,
ifelse(thereArePDL,' with PDL expansion',''),
ifelse(thereAreErrorCorr,' with ERROR autocorrelation TSRANGE extension',''),
') in behavioral "',
eqList[eqIdx],'"\ndoes not overlap with TSRANGE ',paste0(localTSRANGE,collapse=','),': ',e$message)
})
}
#check regressor has NA
if (any(! is.finite(tempRegressor)))
stop('\n ESTIMATE(): there are undefined values in expression "',
currentBehavioral$eqRegressorsNames[idxRegrs],
'" (regressor #',idxRegrs,ifelse(thereArePDL,' with PDL expansion',''),
')\n inside the TSRANGE of behavioral "',eqList[eqIdx],'"\n',sep='')
#adde evaluated regressor to X matrix
bm_matrixX=cbind(bm_matrixX,tempRegressor)
}#end regressor generating cycle
#now we have X matrix
#project y
bm_vectorY=localE[[eqList[eqIdx]]]
#deal with LHS funs
if (currentBehavioral$lhsFun$funName!='I')
{
tryCatch({
if (currentBehavioral$lhsFun$funName=='LOG')
{
bm_vectorY=log(bm_vectorY)
} else if (currentBehavioral$lhsFun$funName=='EXP')
{
bm_vectorY=exp(bm_vectorY)
} else if (currentBehavioral$lhsFun$funName=='TSDELTA' || currentBehavioral$lhsFun$funName=='DEL')
{
if (currentBehavioral$lhsFun$argsCount>1 && ! is.finite(as.numeric(currentBehavioral$lhsFun$args[2])))
stop('Non-numeric lag in TSDELTA()')
if (currentBehavioral$lhsFun$argsCount>1) tmpV=as.numeric(currentBehavioral$lhsFun$args[2])
else tmpV=1
bm_vectorY=TSDELTA(bm_vectorY,tmpV)
} else if (currentBehavioral$lhsFun$funName=='TSDELTAP' )
{
if (currentBehavioral$lhsFun$argsCount>1 && ! is.finite(as.numeric(currentBehavioral$lhsFun$args[2])))
stop('Non-numeric lag in TSDELTAP()')
if (currentBehavioral$lhsFun$argsCount>1) tmpV=as.numeric(currentBehavioral$lhsFun$args[2])
else tmpV=1
bm_vectorY=TSDELTAP(bm_vectorY,tmpV)
} else if (currentBehavioral$lhsFun$funName=='TSDELTALOG' )
{
if (currentBehavioral$lhsFun$argsCount>1 && ! is.finite(as.numeric(currentBehavioral$lhsFun$args[2])))
stop('Non-numeric lag in TSDELTALOG()')
if (currentBehavioral$lhsFun$argsCount>1) tmpV=as.numeric(currentBehavioral$lhsFun$args[2])
else tmpV=1
bm_vectorY=TSDELTALOG(bm_vectorY,tmpV)
}
},error=function(e)
{
stop('ESTIMATE(): error in LHS caclulation of "',currentBehavioral$lhsFun$raw,'" in behavioral "',eqList[eqIdx],'"',': ',e$message)
})
}
tryCatch({
bm_vectorY=(TSPROJECT(bm_vectorY,TSRANGE=localTSRANGE,ARRAY=TRUE,avoidCompliance=TRUE))
#check vector Y size
if (length(bm_vectorY)!=regressorLengthTest) stop()
},error=function(e)
{
stop('ESTIMATE(): LHS expression "',
currentBehavioral$lhsFun$raw, '" in behavioral "',eqList[eqIdx],'" does not overlap with TSRANGE ',
paste0(localTSRANGE,collapse=','),': ',e$message)
})
#check Y has NA
if (any(! is.finite(bm_vectorY)))
stop('\n ESTIMATE(): there are undefined values in LHS expression "',
currentBehavioral$lhsFun$raw, '" inside the TSRANGE of behavioral "',eqList[eqIdx],'"\n',sep='')
#now we have vector Y
thereAreRestrictions=FALSE
bm_restrictionsNum=0
#deal with restrictions
if (!(is.null(currentBehavioral$restrictRaw) ||
is.null(currentBehavioral$vectorR) ||
is.null(currentBehavioral$matrixR) ))
{
thereAreRestrictions=TRUE
}
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
{
bm_matrixR=c()
bm_vectorR=c()
if (thereAreRestrictions == TRUE && thereArePDL == TRUE)
{
bm_matrixR=rbind(currentBehavioral$matrixR,currentBehavioral$pdlRestrictionMatrix)
bm_vectorR=c(currentBehavioral$vectorR,currentBehavioral$pdlRestrictionVector)
}
else if (thereArePDL == TRUE ) {
bm_matrixR=currentBehavioral$pdlRestrictionMatrix
bm_vectorR=currentBehavioral$pdlRestrictionVector
thereAreRestrictions=TRUE
} else {
#extract restriction from model definition
bm_matrixR=currentBehavioral$matrixR
bm_vectorR=currentBehavioral$vectorR
}
bm_restrictionsNum=length(bm_vectorR)
}
#obs count
bm_numObs=1+NUMPERIOD(c(localTSRANGE_bk[1],localTSRANGE_bk[2]),c(localTSRANGE_bk[3],localTSRANGE_bk[4]),frequency)
#degree of freedom
bm_DoF=bm_numObs-bm_coeffNum+bm_restrictionsNum-bm_errorDim
statsOut$DegreesOfFreedom=bm_DoF
#check consistence of regression
if (bm_DoF<0) stop('ESTIMATE(): negative count of degrees of freedom in behavioral "',eqList[eqIdx],'".')
if (bm_DoF==0) .MODEL_outputText(outputText=!quietly,paste0('ESTIMATE(): warning, zero degrees of freedom in behavioral "',eqList[eqIdx],'". Other warnings and errors may arise.\n'))
# CO start --------------------------------------------------------
#used in CO error autocorrelation
bm_COlastIter=FALSE
#cycle multiple time if error correlation required, else just 1 time
for (bm_COcurrentIter in 1:bm_COmaxIters)
{
#this is skipped anyway on first iteration
if ((thereAreErrorCorr==TRUE) && (bm_COcurrentIter>1))
{
#CO transformation
#backup original vector and matrix
bm_vectorY_bk=bm_vectorY
bm_matrixX_bk=bm_matrixX
if (estTech=='IV') bm_matrixZ_bk=bm_matrixZ
#CO transform
bm_vectorY=bm_resP %*% bm_vectorY
bm_matrixX=bm_resP %*% bm_matrixX
#in CO betaHat is calculated on original tsrange
bm_vectorY=bm_vectorY[(1+bm_errorDim):length(bm_vectorY)]
bm_matrixX=bm_matrixX[(1+bm_errorDim):nrow(bm_matrixX),]
if (estTech=='IV') bm_matrixZ=bm_matrixZ[(1+bm_errorDim):nrow(bm_matrixZ),]
}
bm_betaHat=c()
#if restriction or pdl with length>degree+1 else OLS
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
{
if (estTech=='OLS')
{
bm_WpX=t(bm_matrixX) %*% bm_matrixX
}
if (estTech=='IV')
{
tryCatch({
bm_matrixXZ=bm_matrixZ %*% solve( crossprod( bm_matrixZ ),
crossprod( bm_matrixZ, bm_matrixX ),
tol=tol)
},error=function(e)
{
stop('ESTIMATE(): given Z = the matrix of the instrumental variables as columns, Z\'*Z is not invertible. Behavioral: "',eqList[eqIdx],'". Check regressors and "IV" or try to reduce tolerance "tol" value. ',e$message)
})
bm_WpX=t(bm_matrixXZ) %*% bm_matrixXZ
}
bm_ave_WpX=base::mean(bm_WpX)
bm_Rscale=c()
for (idxRscale in 1:dim(bm_matrixR)[1])
{
bm_Rscale=c(bm_Rscale,bm_ave_WpX/max(abs(bm_matrixR[idxRscale,])))
}
bm_matrixR_tx=bm_matrixR*bm_Rscale
if (dim(bm_WpX)[1] != dim(bm_matrixR_tx)[2]) stop('ESTIMATE(): elements size mismatch in restriction augmented-cross product calculation. Behavioral: "',eqList[eqIdx],'".')
bm_AWpX=rbind(bm_WpX,bm_matrixR_tx)
bm_AmatrixR=cbind(bm_matrixR_tx,matrix(rep(0,dim(bm_matrixR_tx)[1]^2),nrow=dim(bm_matrixR_tx)[1]))
bm_AAWpX=cbind(bm_AWpX,t(bm_AmatrixR))
if (estTech=='OLS') bm_AvectorY=c(t(bm_matrixX) %*% bm_vectorY,bm_vectorR * bm_Rscale)
if (estTech=='IV') bm_AvectorY=c(t(bm_matrixXZ) %*% bm_vectorY,bm_vectorR * bm_Rscale)
tryCatch({
bm_AAWpXi =solve(bm_AAWpX,
tol=tol)
bm_betaHat=bm_AAWpXi %*% bm_AvectorY
bm_betaHat=bm_betaHat[1:dim(bm_matrixX)[2],,drop=F]
},error=function(e)
{
stop('ESTIMATE(): in restriction ',currentBehavioral$restrictRaw,
' given betaHat = (W\'X)^(-1) * (W\'Y), W\'X is not invertible. Behavioral: "',eqList[eqIdx],'". Check regressors or try to reduce tolerance "tol" value. ',e$message)
})
#get f-statistics for restrictions
#unrestricted beta OLS
if (estTech=='OLS') {
#check inverse exist
bm_matrixXpXinv=NULL
tryCatch({
bm_matrixXpXinv=solve(t(bm_matrixX) %*% bm_matrixX,
tol=tol)
},error=function(e)
{
stop('ESTIMATE(): given y = X * b + u, X\'*X is not invertible (un-restricted case in F-test). Behavioral: "',eqList[eqIdx],'". Check regressors or try to reduce tolerance "tol" value. ',e$message)
})
#OLS unrestricted :)
bm_betaHat_unrestricted=bm_matrixXpXinv %*% t(bm_matrixX) %*% bm_vectorY
}
#get f-statistics for restrictions
#unrestricted beta IV
if (estTech=='IV') {
#check inverse exist
bm_matrixXpXinv=NULL
tryCatch({
bm_matrixXpXinv=solve( crossprod( bm_matrixXZ ),
tol=tol)
bm_betaHat_unrestricted=bm_matrixXpXinv %*% crossprod( bm_matrixXZ, bm_vectorY )
},error=function(e)
{
stop('ESTIMATE(): given y = X * b + u and given Z = the matrix of the instrumental variables as columns, and X_hat = Z * ( Z\' * Z )^(-1) * Z\' * X, X_hat\'*X_hat is not invertible (un-restricted case in F-test). Behavioral: "',eqList[eqIdx],'". Check regressors or try to reduce tolerance "tol" value. ',e$message)
})
}
} else
{
#no restriction
#default OLS
if (estTech=='OLS') {
#check inverse exist
bm_matrixXpXinv=NULL
tryCatch({
bm_matrixXpXinv=solve(t(bm_matrixX) %*% bm_matrixX,
tol=tol)
},error=function(e)
{
stop('ESTIMATE(): given y = X * b + u, X\'*X is not invertible. Behavioral: "',eqList[eqIdx],'". Check regressors or try to reduce tolerance "tol" value. ',e$message)
})
#OLS :)
bm_betaHat=bm_matrixXpXinv %*% t(bm_matrixX) %*% bm_vectorY
}
if (estTech=='IV') {
#check inverse exist
bm_matrixXpXinv=NULL
tryCatch({
bm_matrixXZ=bm_matrixZ %*% solve( crossprod( bm_matrixZ ),
crossprod( bm_matrixZ, bm_matrixX ),
tol=tol )
},error=function(e)
{
stop('ESTIMATE(): given Z = the matrix of the instrumental variables as columns, Z\'*Z is not invertible. Behavioral: "',eqList[eqIdx],'". Check regressors and "IV" or try to reduce tolerance "tol" value. ',e$message)
})
tryCatch({
bm_matrixXpXinv=solve( crossprod( bm_matrixXZ ),
tol=tol)
bm_betaHat=bm_matrixXpXinv %*% crossprod( bm_matrixXZ, bm_vectorY )
},error=function(e)
{
stop('ESTIMATE(): given y = X * b + u and given Z = the matrix of the instrumental variables as columns, and X_hat = Z * ( Z\' * Z )^(-1) * Z\' * X, X_hat\'*X_hat is not invertible. Behavioral: "',eqList[eqIdx],'". Check regressors and "IV" or try to reduce tolerance "tol" value. ',e$message)
})
}
} # end if no restriction
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
{
statsOut$matrixXaug=bm_AAWpX
statsOut$vectorYaug=bm_AvectorY
}
#deal with error correlations
if ((thereAreErrorCorr==TRUE) && (bm_COcurrentIter>1))
{
#restore original Y and X (the longer ones...): we need extended regressor in order to have coherent errors lags
bm_vectorY=bm_vectorY_bk
bm_matrixX=bm_matrixX_bk
if (estTech=='IV') bm_matrixZ=bm_matrixZ_bk
}
#exit from loop if convergence reached (variable set later...)
if (bm_COlastIter==TRUE) break
#these are residuals
bm_unSquare=bm_vectorY - bm_matrixX %*% bm_betaHat
#f-statistics for restrictions
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
bm_unSquare_unrestricted=bm_vectorY - bm_matrixX %*% bm_betaHat_unrestricted
#perform OLS on errors: u=LAG(u)*rho + z
if (thereAreErrorCorr==TRUE)
{
#cochrane orcutt evaluation
#OLS on AR(bm_errorDim) on residuals
bm_resX=NULL
bm_resY=NULL
#project residuals on original tsrange
if (length(bm_unSquare)<(bm_errorDim+1))
stop('ESTIMATE(): order of error autocorrelation greater than either available observations or TSRANGE specifications (Cochrane-Orcutt). Behavioral: "',eqList[eqIdx],'".')
bm_resY=bm_unSquare[(1+bm_errorDim):length(bm_unSquare)]
#create lagged residuals
for(idxRS in 1:bm_errorDim)
{
bm_resX=cbind(bm_resX,bm_unSquare[(1+bm_errorDim-idxRS):(length(bm_unSquare)-idxRS)])
}
#check inverse exist
bm_matrixresXpresXinv=NULL
tryCatch({
bm_matrixresXpresXinv=solve(t(bm_resX) %*% bm_resX,
tol=tol)
},error=function(e)
{
stop('ESTIMATE(): given u = LAG(u) * rho + z, LAG(u)\'*LAG(u) is not invertible (Cochrane-Orcutt). Behavioral: "',
eqList[eqIdx],'". Check residuals or try to reduce tolerance "tol" value. ',e$message)
})
#there are error autocorrelation coefficients
bm_rhoHat=bm_matrixresXpresXinv %*% t(bm_resX) %*% bm_resY
#deal with regression standard errors...
bm_COunSquare=bm_resY-bm_resX %*% bm_rhoHat
bm_COuSquare=bm_COunSquare * bm_COunSquare
bm_COssr=sum(bm_COuSquare)
bm_COcoeffNum=bm_errorDim
bm_COnumObs=1+NUMPERIOD(c(localTSRANGE_bk[1],localTSRANGE_bk[2]),c(localTSRANGE_bk[3],localTSRANGE_bk[4]),frequency)
#bm_COser=sqrt(bm_COssr/(bm_COnumObs-bm_COcoeffNum))
if (bm_COnumObs - bm_COcoeffNum - bm_coeffNum +bm_restrictionsNum==0) tmpV=0
else tmpV=sqrt((bm_COssr-(sum(bm_COunSquare)^2)/bm_COnumObs)/
(bm_COnumObs - bm_COcoeffNum - bm_coeffNum + bm_restrictionsNum)) #...dont know why bm_COcoeffNum and bm_restrictionsNum
bm_COser=tmpV
bm_COserAdj=bm_COser
if (bm_COnumObs - bm_COcoeffNum - bm_coeffNum +bm_restrictionsNum==0) tmpV=0
else tmpV=sqrt((bm_COssr)/
(bm_COnumObs - bm_COcoeffNum - bm_coeffNum + bm_restrictionsNum)) #...dont know why bm_COcoeffNum and bm_restrictionsNum
if (!centerCOV) bm_COserAdj=tmpV
bm_COvcov=(bm_COserAdj*bm_COserAdj) * bm_matrixresXpresXinv
bm_COstderr=sqrt(diag(bm_COvcov))
statsOut$RhosCovariance=bm_COvcov
rownames(statsOut$RhosCovariance)=paste0("RHO_",1:(bm_COcoeffNum))
colnames(statsOut$RhosCovariance)=paste0("RHO_",1:(bm_COcoeffNum))
#create CO transf matrix (P matrix in user guide)
bm_realTSRANGEobs=1+NUMPERIOD(c(localTSRANGE[1],localTSRANGE[2]),c(localTSRANGE[3],localTSRANGE[4]),frequency)
bm_resP=matrix(rep(0,bm_realTSRANGEobs^2),nrow=bm_realTSRANGEobs)
#bm_repP is modifier for original Y and X
for (idxP in 1:bm_realTSRANGEobs)
{
bm_resP[idxP,idxP]=1
for (idxRS in 1:bm_errorDim)
{
if (idxP>idxRS) bm_resP[idxP,idxP-idxRS]=-bm_rhoHat[idxRS]
}
}
#set flag if convergence (we need at least 1 iteration in order to get betahat with current rho)
if (bm_COcurrentIter>1)
{
#convergence check
if (all(abs(bm_rhoHat-bm_COprevRho)<bm_COconvergence)) bm_COlastIter=TRUE
#if (sqrt(sum((bm_rhoHat-bm_COprevRho)^2))/sqrt(sum(bm_COprevRho^2)) < bm_COconvergence) bm_COlastIter=TRUE
}
#save results for next iteration
bm_COprevRho=bm_rhoHat
}#end thereAreErrorCorr
#take stop between iterations
}#end CO iteration
# CO end --------------------------------------------------
if (thereAreErrorCorr==TRUE)
{
#restore localRANGE
localTSRANGE=localTSRANGE_bk
.MODEL_outputText(outputText=outputText,'\nConvergence reached in ',bm_COcurrentIter,' iterations.\n\n')
}
bm_unSquare_no_error_correction=NULL
#in error correlation cases, u must be calculated by using transformed y and x
if ((thereAreErrorCorr==TRUE))
{
#transom with matrix P
bm_vectorY=bm_resP %*% bm_vectorY
bm_matrixX=bm_resP %*% bm_matrixX
#project on localTSRANGE
bm_vectorY=bm_vectorY[(1+bm_errorDim):length(bm_vectorY)]
bm_matrixX=bm_matrixX[(1+bm_errorDim):nrow(bm_matrixX),]
#save regressors and y (with ERROR> we save the modified ones)
statsOut$matrixX_error_corrected=as.matrix(bm_matrixX)
statsOut$vectorY_error_corrected=as.matrix(bm_vectorY)
colnames(statsOut$matrixX_error_corrected)=currentBehavioral$eqRegressorsNames
colnames(statsOut$vectorY_error_corrected)=currentBehavioral$lhsFun$raw
#calc error
bm_unSquare= bm_vectorY - bm_matrixX %*% bm_betaHat
#f-statistics for restrictions
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
bm_unSquare_unrestricted=bm_vectorY - bm_matrixX %*% bm_betaHat_unrestricted
#restore vectors
bm_vectorY=bm_vectorY_bk
bm_matrixX=bm_matrixX_bk
bm_vectorY=bm_vectorY[(1+bm_errorDim):length(bm_vectorY)]
bm_matrixX=bm_matrixX[(1+bm_errorDim):nrow(bm_matrixX),]
bm_unSquare_no_error_correction=bm_vectorY - bm_matrixX %*% bm_betaHat
}
bm_uSquare=bm_unSquare * bm_unSquare
#save regressors and y
statsOut$matrixX=as.matrix(bm_matrixX)
statsOut$vectorY=as.matrix(bm_vectorY)
colnames(statsOut$matrixX)=currentBehavioral$eqRegressorsNames
colnames(statsOut$vectorY)=currentBehavioral$lhsFun$raw
#sum squared residuals
bm_ssr=sum(bm_uSquare)
#check residuals length
if (NUMPERIOD(localTSRANGE[1:2],localTSRANGE[3:4],frequency) +1 != length(bm_unSquare))
{
stop(paste0('ESTIMATE(): unknown error on residuals length in behavioral ',eqList[eqIdx]))
}
#time series for residuals
bm_unSquareTS=TSERIES(bm_unSquare,START=localTSRANGE[1:2],FREQ=frequency,avoidCompliance=TRUE)
if ((thereAreErrorCorr==TRUE) ) bm_unSquare_no_error_correctionTS=TSERIES(bm_unSquare_no_error_correction,START=localTSRANGE[1:2],FREQ=frequency,avoidCompliance=TRUE)
statsOut$estimationTechnique=estTech
statsOut$TSRANGE=localTSRANGE
statsOut$InstrumentalVariablesRaw=IV
statsOut$tol=tol
statsOut$digits=digits
statsOut$centerCOV=centerCOV
#standard error regression
#bm_ser=sqrt(bm_ssr/(bm_numObs-bm_coeffNum+bm_restrictionsNum))
#here below is centered
if (bm_DoF==0) tmpV=0
else tmpV=sqrt((bm_ssr-(sum(bm_unSquare)^2)/bm_numObs)/(bm_DoF))
bm_ser=tmpV
bm_serAdj=bm_ser
if (bm_DoF==0) tmpV=0
else tmpV=sqrt((bm_ssr)/(bm_DoF))
if (!centerCOV) bm_serAdj=tmpV
statsOut$StandardErrorRegression=bm_ser
if (bm_DoF==0) tmpV=0
else tmpV=sqrt((bm_ssr)/(bm_DoF))
statsOut$StandardErrorRegressionNotCentered=tmpV
#var-covar coeff
if ( ! thereAreRestrictions)
{
bm_vcov=(bm_serAdj*bm_serAdj) * bm_matrixXpXinv
#bm_vcov=vcov(linear_model)
} else {
bm_vcov=(bm_serAdj*bm_serAdj) * bm_AAWpXi
}
#in model with restrictions, diagonal cov elements can be very small but negatives... so abs(diag()) here below
#coeff of variation betaHat
#if restrictions size vcov != size betaHat
bm_vcov=bm_vcov[1:length(bm_betaHat),1:length(bm_betaHat),drop=F]
suppressWarnings({bm_betaHatStdErr=sqrt(abs(diag(bm_vcov)))}) #we have warnings if restrictions due to NAs
#bm_betaHatStdErr=bm_betaHatStdErr[1:length(bm_betaHat)]
#remove 0/0 cases
bm_betaHatCoV=bm_betaHat/bm_betaHatStdErr
if (any(is.nan(bm_betaHatCoV))) bm_betaHatCoV[which(is.nan(bm_betaHatCoV))]=Inf
names(bm_betaHatCoV)=currentBehavioral$eqCoefficientsNames
#bm_vcovOut=bm_vcov[1:length(bm_betaHat),1:length(bm_betaHat),drop=FALSE]
rownames(bm_vcov)=currentBehavioral$eqCoefficientsNames
colnames(bm_vcov)=currentBehavioral$eqCoefficientsNames
statsOut$CoeffCovariance=bm_vcov
statsOut$CoeffTstatistic=bm_betaHatCoV
# R & SPK differs in Rsquared, we choosed R
if (bm_ConstTermExist) tmpV=ave(bm_vectorY)
else tmpV=0
bm_rSquared=1-(bm_ssr)/(sum((bm_vectorY-tmpV)^2))
#we keep old code just as reminder
# #r-squared
# if (thereAreErrorCorr==TRUE )
# {
# #this is ok even without error correlation - DEFAULT R lm formula
# bm_rSquared=1-(bm_ssr)/(sum((bm_vectorY - ave(bm_vectorY) )^2)) #eq by wiki works fine with error autocorrelation
#
# }
#
# if ((thereAreRestrictions == TRUE ||
# (thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix)))))
# {
# # DEFAULT SPK
#
# #eq by user guide
# bm_rSquared_tempY=bm_matrixX %*% bm_betaHat
#
# bm_rSquared=(sum((bm_vectorY-base::mean(bm_vectorY))*(((bm_rSquared_tempY)-base::mean(bm_rSquared_tempY))))^2)/
# ((sum((((bm_rSquared_tempY)-base::mean(bm_rSquared_tempY))^2)))*(sum((bm_vectorY-base::mean(bm_vectorY))^2)))
#
# }
statsOut$RSquared=bm_rSquared
#adj r-squared
#R lm default formula
if (bm_ConstTermExist) tmpV2=1
else tmpV2=0
if (bm_DoF==0) tmpV=1
else tmpV=1-(1-bm_rSquared)*(bm_numObs-tmpV2)/(bm_DoF)
bm_adjrSquared=tmpV #+1-1
if ((thereAreErrorCorr==TRUE ) || ((thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))))
{
if (bm_DoF==0) tmpV=1
else tmpV=1-(1-bm_rSquared)*(bm_numObs- 1)/(bm_DoF)
bm_adjrSquared=tmpV #+1-1
}
statsOut$AdjustedRSquared=bm_adjrSquared
#assign beta hat to coefficients
currentBehavioral$coefficients=bm_betaHat
if (thereAreErrorCorr==TRUE) rownames(bm_rhoHat)=paste0("RHO_",1:(bm_COcoeffNum))
if (thereAreErrorCorr==TRUE) currentBehavioral$errorCoefficients=bm_rhoHat
if (length(currentBehavioral$coefficients) !=
length(currentBehavioral$eqCoefficientsNames))
{
stop('ESTIMATE(): coefficients count differs from coefficients names length.')
}
rownames(currentBehavioral$coefficients)=currentBehavioral$eqCoefficientsNames
#save residuals
currentBehavioral$residuals=bm_unSquareTS
if (thereAreErrorCorr==TRUE) currentBehavioral$residuals_no_error_correction=bm_unSquare_no_error_correctionTS
#f-statistics for restrictions
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
{
bm_uSquare_unrestricted=bm_unSquare_unrestricted * bm_unSquare_unrestricted
#sum squared residuals not restricted
bm_ssr_unrestricted=sum(bm_uSquare_unrestricted)
#f-test for restrictions
if( thereAreRestrictions==TRUE )
{
if (bm_numObs-bm_coeffNum-bm_errorDim<=0) tmpV=NA
else tmpV=((bm_ssr-bm_ssr_unrestricted )/bm_restrictionsNum)/((bm_ssr_unrestricted)/(bm_numObs-bm_coeffNum-bm_errorDim))
bm_Ftest_restriction=tmpV
if (bm_numObs-bm_coeffNum-bm_errorDim<=0) tmpV=NA
else tmpV=((1-pf(bm_Ftest_restriction,bm_restrictionsNum,bm_numObs-bm_coeffNum)))
bm_Ftest_probability=tmpV
}
}
#calc p-values
pValues=bm_betaHat*0
if (bm_DoF>0) pValues=2*pt(-abs(bm_betaHatCoV),df=bm_DoF)
statsOut$CoeffPvalues=pValues
#print stuff in screen
#print estimated eq data
stdFormat=paste0("%-",digits+5,".",digits,'g')
stdFormatS=paste0("%-",digits+5,'s')
for (idxCoeff in 1:length(bm_betaHat))
{
tmpSign='+'
if (bm_betaHat[idxCoeff]<0) tmpSign='-'
tmpPrefix=paste0(sprintf("%-20s",''),tmpSign,' ')
if (idxCoeff==1) {
if (bm_betaHat[idxCoeff]<0) {
tmpPrefix=paste0(sprintf("%-18s",currentBehavioral$lhsFun$raw),'= - ')
} else {
tmpPrefix=paste0(sprintf("%-20s",currentBehavioral$lhsFun$raw),'= ')
}
}
suffix=''
if (grepl(strongCharOnNumbs,currentBehavioral$eqRegressorsNames[idxCoeff]))
{
if(currentBehavioral$eqRegressorsNames[idxCoeff]!='1')
suffix=paste0('CONST*',currentBehavioral$eqRegressorsNames[idxCoeff])
} else {
suffix=paste0(currentBehavioral$eqRegressorsNames[idxCoeff])
}
if (thereArePDL==FALSE)
{
#if modify these lines also modify below
#print tmpPrefix (+ or -) then coeff value then regressor eq
.MODEL_outputText(outputText=outputText,'\n',tmpPrefix,sprintf(stdFormat,abs(bm_betaHat[idxCoeff])),suffix,'\n',sep='')
#if restricted print string else CoV
tmpCoV=bm_betaHatCoV[idxCoeff]
if (! is.finite(tmpCoV) || abs(tmpCoV)>1e9)
{
tmpCoV='RESTRICT'
} else
{
localPvalueS=''
#if (pValues[idxCoeff]<0.1) localPvalueS='.'
if (pValues[idxCoeff]<0.05) localPvalueS='*'
if (pValues[idxCoeff]<0.01) localPvalueS='**'
if (pValues[idxCoeff]<0.001) localPvalueS='***'
tmpCoV=sprintf(stdFormat,tmpCoV)
tmpCoV=paste0('T-stat. ',tmpCoV,localPvalueS)
}
.MODEL_outputText(outputText=outputText,sprintf("%-24s",''),tmpCoV,'\n',sep='')
} else {
if (! currentBehavioral$eqCoefficientsNames[idxCoeff] %in% currentBehavioral$eqCoefficientsNamesOriginal ) next
tmpMatrix=currentBehavioral$pdlMatrix
tmpCoeff=currentBehavioral$eqCoefficientsNames[idxCoeff]
tmpOrigCoeff=currentBehavioral$eqCoefficientsNamesOriginal
tmpIdxinOriginal=which(tmpOrigCoeff==tmpCoeff)
#if coefficient has pdl
if (tmpMatrix[1,tmpIdxinOriginal]==1)
{
#print coeff name if pdl instead of value
.MODEL_outputText(outputText=outputText,'\n',gsub('-','+',tmpPrefix),sprintf(stdFormatS,currentBehavioral$eqCoefficientsNames[idxCoeff]),suffix,'\n',sep='')
.MODEL_outputText(outputText=outputText,sprintf("%-24s",''),'PDL\n',sep='')
} else {
#print tmpPrefix (+ or -) then coeff value then regressor eq
.MODEL_outputText(outputText=outputText,'\n',tmpPrefix,sprintf(stdFormat,abs(bm_betaHat[idxCoeff])),suffix,'\n',sep='')
#if restricted print string else CoV
tmpCoV=bm_betaHatCoV[idxCoeff]
if (! is.finite(tmpCoV) || abs(tmpCoV)>1e9)
{
tmpCoV='RESTRICT'
} else
{
localPvalueS=''
#if (pValues[idxCoeff]<0.1) localPvalueS='.'
if (pValues[idxCoeff]<0.05) localPvalueS='*'
if (pValues[idxCoeff]<0.01) localPvalueS='**'
if (pValues[idxCoeff]<0.001) localPvalueS='***'
tmpCoV=sprintf(stdFormat,tmpCoV)
tmpCoV=paste0('T-stat. ',tmpCoV,localPvalueS)
}
.MODEL_outputText(outputText=outputText,sprintf("%-24s",''),tmpCoV,'\n',sep='')
}
}
}
#durbin watson
bm_dw=NA
if (bm_numObs>1) {
if (thereAreErrorCorr==TRUE)
{
bm_vectorY=bm_vectorY_bk
bm_matrixX=bm_matrixX_bk
bm_vectorY=bm_resP %*% bm_vectorY
bm_matrixX=bm_resP %*% bm_matrixX
bm_vectorY=bm_vectorY[(1+bm_errorDim):length(bm_vectorY)]
bm_matrixX=bm_matrixX[(1+bm_errorDim):nrow(bm_matrixX),]
}
bm_tmp_dw=bm_vectorY - bm_matrixX %*% bm_betaHat
for (idxdw in 2:length(bm_tmp_dw)) bm_dw[idxdw-1]=bm_tmp_dw[idxdw]-bm_tmp_dw[idxdw-1]
bm_dw=bm_dw*bm_dw
bm_dw=sum(bm_dw)
bm_dw=bm_dw/bm_ssr
#restore originals
if (thereAreErrorCorr==TRUE)
{
bm_vectorY=bm_vectorY_bk
bm_matrixX=bm_matrixX_bk
bm_vectorY=bm_vectorY[(1+bm_errorDim):length(bm_vectorY)]
bm_matrixX=bm_matrixX[(1+bm_errorDim):nrow(bm_matrixX),]
}
}
#log likelihood
bm_loglike=-(bm_numObs/2)*(1+log(2*pi)+log(bm_ssr/bm_numObs))
#Akaike
bm_AIC=2*(1+bm_coeffNum-bm_restrictionsNum+bm_errorDim)-2*bm_loglike
#Schwarz
bm_BIC=log(bm_numObs)*(1+bm_coeffNum-bm_restrictionsNum+bm_errorDim)-2*bm_loglike
if (thereAreErrorCorr==TRUE)
{
.MODEL_outputText(outputText=outputText,'\nERROR STRUCTURE: ',bm_errorRaw,'\n')
}
if (bm_ConstTermExist) tmpV2=1
else tmpV2=0
if (bm_DoF==0) tmpV=+Inf
else tmpV=(bm_rSquared/(bm_coeffNum-tmpV2+bm_errorDim-bm_restrictionsNum))*
((bm_DoF)/(1-bm_rSquared))
bm_fStat=tmpV
if (is.finite(bm_fStat) && bm_DoF>0) tmpV=1-pf(bm_fStat,bm_coeffNum-tmpV2+bm_errorDim-bm_restrictionsNum,bm_DoF)
else tmpV=1
bm_fProb=tmpV
if (thereAreRestrictions && (! is.null(currentBehavioral$restrictRaw)))
{
.MODEL_outputText(outputText=outputText,'\nRESTRICTIONS:')
.MODEL_outputText(outputText=outputText,'\n')
.MODEL_outputText(outputText=outputText,paste(strsplit(currentBehavioral$restrictRaw,';')[[1]],collapse='\n'))
.MODEL_outputText(outputText=outputText,'\n')
}
if (thereArePDL == TRUE)
{
.MODEL_outputText(outputText=outputText,'\nPDL:\n')
.MODEL_outputText(outputText=outputText,paste(strsplit(currentBehavioral$pdlRaw,';')[[1]],collapse='\n'))
tmpCoeff=currentBehavioral$eqCoefficientsNames
.MODEL_outputText(outputText=outputText,'\n')
for(idxPrintPDL in (which(bm_pdlMatrix[1,]==1)))
{
.MODEL_outputText(outputText=outputText,'\n')
tmpLaggedCoeff=currentBehavioral$eqCoefficientsNamesOriginal[idxPrintPDL]
.MODEL_outputText(outputText=outputText,'Distributed Lag Coefficient:',tmpLaggedCoeff)
.MODEL_outputText(outputText=outputText,'\n')
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",8,"s"),'Lag'),
sprintf(paste0("%-",digits+8,"s"),'Coeff.'),
sprintf(paste0("%-",digits+8,"s"),'Std. Error'),
sprintf(paste0("%-",digits+8,"s"),'T-stat.'),
'\n',sep='')
posCoeffInCoeffArray=which(tmpCoeff==tmpLaggedCoeff)
tmpSum=0
for(idxPrintSinglePDL in 0:(bm_pdlMatrix[3,idxPrintPDL]-1))
{
tmpValue=bm_betaHat[posCoeffInCoeffArray+idxPrintSinglePDL]
tmpSum=tmpSum+tmpValue
if(idxPrintSinglePDL==0 && bm_pdlMatrix[4,idxPrintPDL]==1)
{#PDL N so this is 0
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",8,"d"),idxPrintSinglePDL),' ',
sprintf(paste0("%-",digits+8,"f"),0),
sprintf(paste0("%-",digits+8,"s"),'RESTRICT'),
sprintf(paste0("%-",digits+8,"s"),'RESTRICT'),'\n',sep='')
} else if(idxPrintSinglePDL==(bm_pdlMatrix[3,idxPrintPDL]-1) && bm_pdlMatrix[5,idxPrintPDL]==1)
{#PDL F so this is 0
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",8,"d"),idxPrintSinglePDL),' ',
sprintf(paste0("%-",digits+8,"f"),0),
sprintf(paste0("%-",digits+8,"s"),'RESTRICT'),
sprintf(paste0("%-",digits+8,"s"),'RESTRICT'),'\n',sep='')
} else {
localErr=bm_betaHatStdErr[posCoeffInCoeffArray+idxPrintSinglePDL]
if (localErr==0) tmpV=Inf
else tmpV=(tmpValue)/localErr
tStat=tmpV
if (bm_DoF==0) tmpV=0
else tmpV=2*pt(-abs(tStat),bm_DoF)
pValue=tmpV
localPvalueS=''
if (pValue<0.05) localPvalueS='*'
if (pValue<0.01) localPvalueS='**'
if (pValue<0.001) localPvalueS='***'
tmpSD=sprintf(paste0("% -",digits+8,".",digits,"g"),bm_betaHatStdErr[posCoeffInCoeffArray+idxPrintSinglePDL])
tmpTstat=sprintf(paste0("% -",digits+8,".",digits,"g"),(tStat))
if (! is.finite(tStat) || abs(tStat)>1e9)
{
tmpSD=sprintf(paste0("%-",digits+8,"s"),' RESTRICT')
tmpTstat=sprintf(paste0("%-",digits+8,"s"),' RESTRICT')
}
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",8,"d"),idxPrintSinglePDL),
sprintf(paste0("% -",digits+8,".",digits,"g"),(tmpValue)),
tmpSD,
tmpTstat,
localPvalueS,
'\n',sep='')
}
}
#get pdl covariance matrix (subset of whole cov matrix)
tmpCovPdlMatrix=bm_vcov[posCoeffInCoeffArray:(posCoeffInCoeffArray+bm_pdlMatrix[3,idxPrintPDL]-1),
posCoeffInCoeffArray:(posCoeffInCoeffArray+bm_pdlMatrix[3,idxPrintPDL]-1)]
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",8,"s"),'SUM'),
sprintf(paste0("% -",digits+8,".",digits,"g"),(tmpSum)),
sprintf(paste0("% -",digits+8,".",digits,"g"),sqrt(sum(tmpCovPdlMatrix))),'\n',sep='')
}
}
if (thereAreRestrictions == TRUE ||
(thereArePDL == TRUE && (! is.null(currentBehavioral$pdlRestrictionMatrix))))
{
.MODEL_outputText(outputText=outputText,'\nRESTRICTIONS F-TEST:\n')
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",16+2,"s"),'F-value'),
sprintf(paste0(":% -",digits+8,".",digits,"g"),(bm_Ftest_restriction)),'\n')
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",16+2,"s"),paste0('F-prob(',bm_restrictionsNum,',',bm_numObs-bm_coeffNum,')')),
sprintf(paste0(":% -",digits+8,".",digits,"g"),(bm_Ftest_probability)),'\n')
statsOut$FtestRestrValue=bm_Ftest_restriction
statsOut$FtestRestrProbability=bm_Ftest_probability
statsOut$FtestRestrDoFs=c(bm_restrictionsNum,bm_numObs-bm_coeffNum)
}
if (thereAreErrorCorr==TRUE)
{
.MODEL_outputText(outputText=outputText,'\nAUTOREGRESSIVE PARAMETERS:\n')
.MODEL_outputText(outputText=outputText,
sprintf(paste0("%-",digits+8,"s"),'Rho'),
sprintf(paste0("%-",digits+8,"s"),'Std. Error'),
sprintf(paste0("%-",digits+8,"s"),'T-stat.'),'\n')
tStat=(bm_rhoHat)/bm_COstderr
pValue=2*pt(-abs(tStat),bm_DoF)
statsOut$RhosTstatistics=tStat
statsOut$RhosPvalues=pValue
rownames(statsOut$RhosTstatistics)=paste0("RHO_",1:bm_COcoeffNum)
rownames(statsOut$RhosPvalues)=paste0("RHO_",1:bm_COcoeffNum)
for (idxRho in 1:length(bm_rhoHat))
{
localPvalueS=''
if (pValue[idxRho]<0.05) localPvalueS='*'
if (pValue[idxRho]<0.01) localPvalueS='**'
if (pValue[idxRho]<0.001) localPvalueS='***'
.MODEL_outputText(outputText=outputText,
sprintf(paste0("% -",digits+8,".",digits,"g"),(bm_rhoHat[idxRho])),
sprintf(paste0("% -",digits+8,".",digits,"g"),bm_COstderr[idxRho]),
sprintf(paste0("% -",digits+8,".",digits,"g"),(tStat[idxRho])),
localPvalueS,'\n')
}
}
.MODEL_outputText(outputText=outputText,'\n\nSTATs:')
.MODEL_outputText(outputText=outputText,'\nR-Squared : ',sprintf(stdFormat,bm_rSquared),sep='')
.MODEL_outputText(outputText=outputText,'\nAdjusted R-Squared : ',sprintf(stdFormat,bm_adjrSquared),sep='')
.MODEL_outputText(outputText=outputText,'\nDurbin-Watson Statistic : ',sprintf(stdFormat,bm_dw),sep='')
.MODEL_outputText(outputText=outputText,'\nSum of squares of residuals : ',sprintf(stdFormat,bm_ssr),sep='')
.MODEL_outputText(outputText=outputText,'\nStandard Error of Regression : ',sprintf(stdFormat,bm_ser),sep='')
.MODEL_outputText(outputText=outputText,'\nLog of the Likelihood Function : ',sprintf(stdFormat,bm_loglike),sep='')
.MODEL_outputText(outputText=outputText,'\nF-statistic : ',sprintf(stdFormat,bm_fStat),sep='')
.MODEL_outputText(outputText=outputText,'\nF-probability : ',sprintf(stdFormat,bm_fProb),sep='')
.MODEL_outputText(outputText=outputText,'\nAkaike\'s IC : ',sprintf(stdFormat,bm_AIC),sep='')
.MODEL_outputText(outputText=outputText,'\nSchwarz\'s IC : ',sprintf(stdFormat,bm_BIC),sep='')
.MODEL_outputText(outputText=outputText,'\nMean of Dependent Variable : ',sprintf(stdFormat,base::mean(bm_vectorY)),sep='')
.MODEL_outputText(outputText=outputText,'\nNumber of Observations : ',bm_numObs,sep='')
.MODEL_outputText(outputText=outputText,'\nNumber of Degrees of Freedom : ',bm_DoF,sep='')
.MODEL_outputText(outputText=outputText,'\nCurrent Sample (year-period) : ',paste0(localTSRANGE[1],'-',localTSRANGE[2],' / ',localTSRANGE[3],'-',localTSRANGE[4]),sep='')
.MODEL_outputText(outputText=outputText,'\n\n\n')
.MODEL_outputText(outputText=outputText,'Signif. codes: *** 0.001 ** 0.01 * 0.05 \n')
.MODEL_outputText(outputText=outputText,'\n')
.MODEL_outputText(outputText=outputText,'\n')
statsOut$DurbinWatson=bm_dw
statsOut$SumSquaresResiduals=bm_ssr
statsOut$LogLikelihood=bm_loglike
statsOut$AIC=bm_AIC
statsOut$BIC=bm_BIC
statsOut$Fstatistics=bm_fStat
statsOut$Fprobability=bm_fProb
statsOut$MeanDependentVariable=base::mean(bm_vectorY)
statsOut$ObservationsCount=bm_numObs
#export stats
currentBehavioral$statistics=statsOut
#save stsuff
model$behaviorals[[eqList[eqIdx]]]=currentBehavioral
CP_provided=FALSE
# CHOW test code ---------------------------------------
if (CHOWTEST==TRUE)
{
#get estimation tsrange
first_estimation_tsrange=currentBehavioral$statistics$TSRANGE
if (is.null(first_estimation_tsrange)) stop('ESTIMATE(): cannot get base estimation TSRANGE of "',eqList[eqIdx],'" during the CHOW test.')
#check if we have a CHOWPAR
if (! is.null(CHOWPAR))
{
CP_provided=TRUE
#check chowpar is beyond end of estimation range
if (NUMPERIOD(c(first_estimation_tsrange[3],first_estimation_tsrange[4]),CHOWPAR,model$frequency)<1)
stop('ESTIMATE(): CHOWPAR ',paste(CHOWPAR,collapse='-'),
' must be beyond the estimation TSRANGE of "',eqList[eqIdx],'" ',
paste(first_estimation_tsrange[1:2],collapse='-'),
' / ',paste(first_estimation_tsrange[3:4],collapse='-'),'.')
# perform second estimation on extended tsrange
tryCatch({
second_model=ESTIMATE(model=model
,TSRANGE=c(first_estimation_tsrange[1],first_estimation_tsrange[2],CHOWPAR[1],CHOWPAR[2])
,forceTSRANGE=TRUE
,eqList=eqList[eqIdx]
,quietly=TRUE
,digits=digits
,CHOWTEST=FALSE #this is mandatory
,tol=tol
,IV=IV
,forceIV=forceIV
,centerCOV=centerCOV
,avoidCompliance=TRUE
,...)
},error=function(e){
stop('ESTIMATE(): error in extended estimation of "',eqList[eqIdx],'", during the CHOW test: ',e$message)
})
} else
{
#CHOWPAR must be auto calculated
#set CHOWPAR to first year-period outsite TSRANGE
CHOWPAR=normalizeYP(c(first_estimation_tsrange[3],first_estimation_tsrange[4]+1),f=frequency)
#perform second estimation on extended tsrange
tryCatch({
second_model=ESTIMATE(model=model
,TSRANGE=c(first_estimation_tsrange[1],first_estimation_tsrange[2],CHOWPAR[1],CHOWPAR[2])
,forceTSRANGE=TRUE
,eqList=eqList[eqIdx]
,quietly=TRUE
,digits=digits
,CHOWTEST=FALSE #this is mandatory
,tol=tol
,IV=IV
,forceIV=forceIV
,centerCOV=centerCOV
,avoidCompliance=TRUE
,...)
},error=function(e){
stop('ESTIMATE(): cannot extend TSRANGE during CHOW test in estimation of "',eqList[eqIdx],'": ',e$message)
})
tryCatch({
#cycle until error in extended range
while(TRUE) {
#try incremental chow pars.
CHOWPAR_tmp=normalizeYP(c(CHOWPAR[1],CHOWPAR[2]+1),f=frequency)
second_model=ESTIMATE(model=model
,TSRANGE=c(first_estimation_tsrange[1],first_estimation_tsrange[2],CHOWPAR_tmp[1],CHOWPAR_tmp[2])
,forceTSRANGE=TRUE
,eqList=eqList[eqIdx]
,quietly=TRUE
,digits=digits
,CHOWTEST=FALSE #this is mandatory
,avoidCompliance=TRUE
,tol=tol
,IV=IV
,forceIV=forceIV
,centerCOV=centerCOV
,...)
#if estimation completes, update the CHOWPAR
CHOWPAR=CHOWPAR_tmp
}
},error=function(e){})
}
baseBehavioral=currentBehavioral
extendedBehavioral=second_model$behaviorals[[eqList[eqIdx]]]
#get first SSR and df
SSR=baseBehavioral$statistics$SumSquaresResiduals
df=baseBehavioral$statistics$DegreesOfFreedom
if (!is.finite(SSR)) .MODEL_outputText(outputText=!quietly,paste0('ESTIMATE(): warning, SSR in first estimation of ',eqList[eqIdx],' is not finite.\n'))
if (!quietly && !is.finite(df)) .MODEL_outputText(outputText=!quietly,paste0('ESTIMATE(): warning, degrees of freedom in first estimation of ',eqList[eqIdx],' are not finite.\n'))
#get second SSR and df
chow_SSR=extendedBehavioral$statistics$SumSquaresResiduals
chow_df=extendedBehavioral$statistics$DegreesOfFreedom
if ( !is.finite(SSR)) .MODEL_outputText(outputText=!quietly,paste0('ESTIMATE(): warning, SSR in second estimation of ',eqList[eqIdx],' is not finite.\n'))
if ( !is.finite(df)) .MODEL_outputText(outputText=!quietly,paste0('ESTIMATE(): warning, degrees of freedom in second estimation of ',eqList[eqIdx],' are not finite.\n'))
if (chow_df==df) .MODEL_outputText(outputText=!quietly,paste0('ESTIMATE(): warning, base and extended estimations of ',eqList[eqIdx],' have the same degrees of freedom\n'))
#out stats
chowOut=list()
#calc stats.
Fchow = (chow_SSR/SSR-1)*chow_df/(chow_df-df)
chowOut$Fvalue=Fchow
DoFchow=c()
DoFchow[1]=chow_df-df
DoFchow[2]=chow_df
chowOut$FtestDegreesOfFreedom=DoFchow
ProbFchow=pf(Fchow,DoFchow[1],DoFchow[2],lower.tail=FALSE)
chowOut$Fprob=ProbFchow
#out of sample simulation RESCHECK
outOfSampleTSRANGE=c(normalizeYP(c(first_estimation_tsrange[3],first_estimation_tsrange[4]+1),f=model$frequency),CHOWPAR)
predOutSample=NULL
tryCatch({
predOutSample=SIMULATE( model,
TSRANGE=outOfSampleTSRANGE,
simType = 'RESCHECK',
simIterLimit=100,
quietly=TRUE,
RESCHECKeqList=eqList[eqIdx],
avoidCompliance=TRUE)
},error=function(e){
stop('ESTIMATE(): error in out-of-sample prediction (extended RESCHECK simulation) of "',eqList[eqIdx],'" during CHOW test: ',e$message)
})
PREDICT =predOutSample$simulation[[eqList[eqIdx]]]
ACTUAL =predOutSample$modelData[[eqList[eqIdx]]]
ERROR =ACTUAL-PREDICT
#fitted standard error calc
fit_se=vector(mode="numeric", length=length(PREDICT))
#get matrices and sers
base_ser =baseBehavioral$statistics$StandardErrorRegression
ext_ser =extendedBehavioral$statistics$StandardErrorRegression
base_matrixX =baseBehavioral$statistics$matrixX
ext_matrixX =extendedBehavioral$statistics$matrixX
base_nobs =baseBehavioral$statistics$ObservationsCount
base_matrixXaug=baseBehavioral$statistics$matrixXaug
ext_matrixXaug =extendedBehavioral$statistics$matrixXaug
tryCatch({
#no restrictions on model
if (is.null(currentBehavioral$matrixR) && is.null(currentBehavioral$pdlRestrictionMatrix))
{
#THIS IS CODE DERIVED FROM STANDARD FORMULA
for (k in 1:(length(PREDICT)))
fit_se[k] = base_ser*sqrt(1+ext_matrixX[base_nobs+k,]%*%solve(t(base_matrixX)%*%base_matrixX)%*%ext_matrixX[base_nobs+k,])
#THIS IS CODE DERIVED FROM SPK RESULTS (probably wrong)
#for (k in 1:(length(PREDICT)))
# fit_se[k] = ext_ser*sqrt(1+ext_matrixX[base_nobs+k,]%*%solve(t(ext_matrixX)%*%ext_matrixX)%*%ext_matrixX[base_nobs+k,])
} else
{
coeffCount=baseBehavioral$eqCoefficientsCount
#THIS IS CODE DERIVED FROM FORMULA
for (k in 1:(length(PREDICT)))
fit_se[k] = base_ser*sqrt(1+ext_matrixX[base_nobs+k,]%*%(solve(base_matrixXaug)[1:coeffCount,1:coeffCount])%*%ext_matrixX[base_nobs+k,])
#THIS IS CODE DERIVED FROM SPK RESULTS
#for (k in 1:(length(PREDICT)))
# fit_se[k] = ext_ser*sqrt(1+ext_matrixX[base_nobs+k,]%*%(solve(ext_matrixXaug)[1:coeffCount,1:coeffCount])%*%ext_matrixX[base_nobs+k,])
}
},error=function(e){
stop('ESTIMATE(): cannot calculate the standard error of "',eqList[eqIdx],'" in year-period ',
paste(normalizeYP(c(outOfSampleTSRANGE[1],outOfSampleTSRANGE[2]+k-1),f=model$frequency),collapse = '-'),' during CHOW test: ',e$message)
})
STDERR=TSERIES(fit_se,START=outOfSampleTSRANGE[1:2],FREQ=model$frequency,avoidCompliance=TRUE)
TSTAT=ERROR/STDERR
#project on tsrange
ACTUAL=TSPROJECT(ACTUAL,TSRANGE=outOfSampleTSRANGE,avoidCompliance=TRUE)
PREDICT=TSPROJECT(PREDICT,TSRANGE=outOfSampleTSRANGE,avoidCompliance=TRUE)
ERROR=TSPROJECT(ERROR,TSRANGE=outOfSampleTSRANGE,avoidCompliance=TRUE)
STDERR=TSPROJECT(STDERR,TSRANGE=outOfSampleTSRANGE,avoidCompliance=TRUE)
TSTAT=TSPROJECT(TSTAT,TSRANGE=outOfSampleTSRANGE,avoidCompliance=TRUE)
chowOut$PredictivePower=list()
chowOut$PredictivePower$ACTUAL=ACTUAL
chowOut$PredictivePower$PREDICT=PREDICT
chowOut$PredictivePower$ERROR=ERROR
chowOut$PredictivePower$STDERR=STDERR
chowOut$PredictivePower$TSTAT=TSTAT
chowOut$TSRANGE=first_estimation_tsrange
chowOut$CHOWPAR=CHOWPAR
#print output
.MODEL_outputText(outputText = !quietly,"\nSTABILITY ANALYSIS:\nBehavioral equation:",eqList[eqIdx],"\n\n")
.MODEL_outputText(outputText = !quietly,"Chow test:\n")
.MODEL_outputText(outputText = !quietly,sprintf(paste0("%-",16+2,"s"),ifelse(!CP_provided,'Sample (auto)','Sample')),
":",paste0(outOfSampleTSRANGE[1:2],collapse='-'),'/',paste0(outOfSampleTSRANGE[3:4],collapse='-'),'\n')
.MODEL_outputText(outputText = !quietly,sprintf(paste0("%-",16+2,"s"),'F-value'),
sprintf(paste0(":% -",digits+8,".",digits,"g"),(Fchow)),'\n')
.MODEL_outputText(outputText = !quietly,
sprintf(paste0("%-",16+2,"s"),paste0('F-prob(',DoFchow[1],',',DoFchow[2],')')),
sprintf(paste0(":% -",digits+8,".",digits,"g"),(ProbFchow)),'\n')
.MODEL_outputText(outputText = !quietly,"\nPredictive Power:\n")
if (!quietly)
{
#change TABIT column names
Actual=ACTUAL
Predict=PREDICT
Error=ERROR
`Std. Error`=STDERR
`T-stat`=TSTAT
TABIT(Actual, Predict, Error, `Std. Error`, `T-stat`, digits=digits)
}
#store results
model$behaviorals[[eqList[eqIdx]]]$ChowTest=chowOut
}#end CHOW test
}#end requested eqs cycle
.MODEL_outputText(outputText=!quietly,'...ESTIMATE OK\n')
return(model)
}
# RENORM code ------------------------------------------------------------------
RENORM <- function(model=NULL,
simAlgo='GAUSS-SEIDEL',
TSRANGE=NULL,
simType='DYNAMIC',
simConvergence=0.01,
simIterLimit=100,
ZeroErrorAC=FALSE,
BackFill=0,
Exogenize=NULL,
ConstantAdjustment=NULL,
verbose=FALSE,
verboseSincePeriod=0,
verboseVars=NULL,
renormIterLimit=10,
renormConvergence=1e-4,
TARGET=NULL,
INSTRUMENT=NULL,
MM_SHOCK=0.00001,
quietly=FALSE,
quietlyMULTMATRIX=FALSE,
tol=1e-28,
JACOBIAN_SHOCK=1e-4,
JacobianDrop=NULL,
forceForwardLooking=FALSE,
avoidCompliance=FALSE,
...)
{
#checks...
if (is.null(model) ) stop('RENORM(): NULL model.')
if (is.null(class( model )) || !(inherits( model ,'BIMETS_MODEL')) )
stop('RENORM(): "model" must be instance of BIMETS_MODEL class.')
if (! (
is.numeric(renormIterLimit) && (renormIterLimit > 0)
) ) stop('RENORM(): "renormIterLimit" must be a positive number.')
if (is.null(TSRANGE) ) stop('RENORM(): "TSRANGE" must be defined.')
if (! is.finite(tol) || tol<=0) stop('RENORM(): please provide a valid tolerance value.')
if (!(is.logical(quietly)) || is.na(quietly)) stop('RENORM(): "quietly" must be TRUE or FALSE.')
if (!(is.logical(quietlyMULTMATRIX)) || is.na(quietlyMULTMATRIX)) stop('RENORM(): "quietlyMULTMATRIX" must be TRUE or FALSE.')
if (quietly) quietlyMULTMATRIX=quietly
if (! (
is.numeric(BackFill) && (BackFill >= 0) && (BackFill %% 1 == 0)
) ) stop('RENORM(): "BackFill" must be zero or a positive integer number.')
if (!(is.logical(verbose))) stop('RENORM(): "verbose" must be TRUE or FALSE.')
if (! avoidCompliance)
{
#check model data
tryCatch({
.CHECK_MODEL_DATA(model,showWarnings=verbose,'RENORM(): ')
},error=function(e){stop('RENORM(): ',e$message)})
}
#reset status
model$renorm=NULL
model$simulation=NULL
#get data frequecy
frequency=frequency(model$modelData[[1]])
#check TSRANGE is consistent
if (! is.null(TSRANGE)) {
tryCatch({
if (! ( is.numeric(TSRANGE) && length(TSRANGE)==4 &&
.isCompliantYP(c(TSRANGE[1],TSRANGE[2]),frequency) &&
.isCompliantYP(c(TSRANGE[3],TSRANGE[4]),frequency) &&
NUMPERIOD(c(TSRANGE[1],TSRANGE[2]),c(TSRANGE[3],TSRANGE[4]),frequency)>=0)
) stop()
},error=function(e) {stop('RENORM(): syntax error in TSRANGE: ',e$message)})
}
#periods in TSRANGE
TSRANGEextension=NUMPERIOD(c(TSRANGE[1],TSRANGE[2]),c(TSRANGE[3],TSRANGE[4]),frequency)+1
#check TARGET
if (is.null(TARGET)) stop('RENORM(): "TARGET" must be defined.')
if (! is.list(TARGET) || length(TARGET)==0)
stop(paste0('RENORM(): "TARGET" must be a list built of endogenous variables as names and related time series as items.'))
for (idxT in names(TARGET))
if (! idxT %in% model$vendog)
stop(paste0('RENORM(): TARGET "',idxT,'" is not a model endogenous variable.'))
#check TARGET is consistent in TSRANGE
for (idxT in 1:length(TARGET))
{
if (! is.bimets(TARGET[[idxT]]))
stop('RENORM(): "TARGET" must be a list of BIMETS time series: "',names(TARGET)[idxT],'" time series is not compliant.')
if (frequency(TARGET[[idxT]])!=frequency)
stop('RENORM(): time series have not the same frequency. Check TARGET time series "',names(TARGET)[idxT],'".')
#project TARGET on TSRANGE
TARGET[[idxT]]=TSPROJECT(TARGET[[idxT]],TSRANGE=TSRANGE,EXTEND=TRUE,avoidCompliance=TRUE)
#deal with missings
if (any(! is.finite(coredata(TARGET[[idxT]]))))
stop('RENORM(): there are undefined values in TSRANGE ',paste0(TSRANGE,collapse='-'),' in TARGET time series "',names(TARGET)[idxT],'"')
}
#check INSTRUMENT
if (is.null(INSTRUMENT) || length(INSTRUMENT)==0)
stop(paste0('RENORM(): "INSTRUMENT" must be defined.'))
for (idxT in 1:length(INSTRUMENT))
{
#check tragets in vendog list
if (! INSTRUMENT[idxT] %in% c(model$vexog,model$vendog))
stop(paste0('RENORM(): INSTRUMENT variable "',INSTRUMENT[idxT] ,
'" is not a model variable.'))
}
if (length(INSTRUMENT) != length(TARGET))
stop(paste0('RENORM(): the targets count must be equal to the instruments count.'))
#check CA vendog exists in model
if (! is.null(ConstantAdjustment))
{
if (! is.list(ConstantAdjustment) )
stop(paste0('RENORM(): "ConstantAdjustment" must be a list built of endogenous variables as names and related time series as items.'))
if (length(ConstantAdjustment) >0)
for (idxCA in names(ConstantAdjustment))
{
#CA has to be a vendog
if (! idxCA %in% model$vendog)
stop(paste0('RENORM(): requested to add a constant adjustment to "',idxCA,'" but it is not a model endogenous variable.'))
if (! is.bimets(ConstantAdjustment[[idxCA]]))
stop('RENORM(): constant adjustment must be a list of BIMETS time series: "',idxCA,'" time series is not compliant.')
#CA needs same frequency as modelData
if (frequency(ConstantAdjustment[[idxCA]])!=frequency(model$modelData[[1]]))
stop('RENORM(): time series do not have the same frequency. Check constant adjustment time series "',idxCA,'".')
#warning about missings
if (any(! is.finite(coredata(ConstantAdjustment[[idxCA]]))))
.MODEL_outputText(outputText=!quietly,'RENORM(): warning, there are undefined values in constant adjustment of the time series "',idxCA,'"\n',sep='')
}
}
#store original INSTRUMENT, in case we need to restore after error
INSTRUMENT_ORIGINAL=list()
INSTRUMENT_CURRENT=list()
for (idxI in 1:length(INSTRUMENT))
{
tmpI=INSTRUMENT[idxI]
if (tmpI %in% model$vexog)
{
#instrument is vexog so get data from model$data
INSTRUMENT_ORIGINAL[[tmpI]]=model$modelData[[tmpI]]
} else if (tmpI %in% model$vendog)
{
#instrument is vendog so get data from CA
if (is.null(ConstantAdjustment[[tmpI]]))
{
#CA does not exist so it is zero...
ConstantAdjustment[[tmpI]]=TSERIES(rep(0,TSRANGEextension),START=TSRANGE[1:2],FREQ=frequency)
INSTRUMENT_ORIGINAL[[tmpI]]=ConstantAdjustment[[tmpI]]
} else
{
INSTRUMENT_ORIGINAL[[tmpI]]=ConstantAdjustment[[tmpI]]
}
}
else stop(paste0('RENORM(): INSTRUMENT variable "', tmpI,
'" is not a model exogenous variable.'))
}
#export some stuff to model
model$renorm[['__RENORM_PARAMETERS__']]$Exogenize=Exogenize
model$renorm[['__RENORM_PARAMETERS__']]$ConstantAdjustment=ConstantAdjustment
model$renorm[['__RENORM_PARAMETERS__']]$renormIterLimit=renormIterLimit
model$renorm[['__RENORM_PARAMETERS__']]$renormConvergence=renormConvergence
if (! is.list(model$simulation)) model$simulation=list()
#init simulated TARGET with historical values
for (idxN in names(TARGET))
{
#get data from historical
model$simulation[[idxN]]=TSPROJECT(model$modelData[[idxN]],TSRANGE=TSRANGE,EXTEND=TRUE,avoidCompliance=TRUE)
}
#main cycle index
renormNIter=0
#get actual TARGETs in TARG_
xxx_=matrix(nrow=length(TARGET),ncol=TSRANGEextension)
for (idxR in 1:length(TARGET))
{
#already projected
xxx_[idxR,]=coredata(TARGET[[idxR]])
}
TARG_=vector('double',length(xxx_))
TARG_=c(xxx_)
#used in convergence
DIFF_=list()
#main cycle
for (renormNIter in 0:renormIterLimit)
{
#names on unconverged TARGETs
unConvergedTARGET=c()
convergenceRenorm=TRUE
#check differences in TARGETs
if (renormNIter>0) for (tmpN in names(TARGET))
{
tmpTs=TSPROJECT(model$simulation[[tmpN]],TSRANGE=TSRANGE,avoidCompliance=TRUE)
DIFF_[[tmpN]]=(TARGET[[tmpN]]-tmpTs)/TARGET[[tmpN]]
if (any(TARGET[[tmpN]]==0))
{
zeroLoc=which(TARGET[[tmpN]]==0)
DIFF_[[tmpN]][zeroLoc]=(TARGET[[tmpN]][zeroLoc]-tmpTs[zeroLoc])
}
#verify convergence
if (sqrt(sum(DIFF_[[tmpN]]^2))>=renormConvergence)
{
unConvergedTARGET=c(unConvergedTARGET,tmpN)
convergenceRenorm=FALSE
}
}
#no convergence
if (convergenceRenorm==FALSE && renormNIter==renormIterLimit)
{
.MODEL_outputText(outputText=!quietly,paste0('\nRENORM(): warning, no convergence in ',renormNIter,' iterations.\n'))
#export unconverged symbols
model$renorm$unConvergedTARGET=unConvergedTARGET
break
}
# enable this code to enable initial TARGET check
# if (convergenceRenorm==TRUE && renormNIter==0)
# {
# .MODEL_outputText(outputText=!quietly,paste0('\nRENORM(): all TARGET are equal to model data. This procedure will exit.\n'))
# break
# }
#convergence
if (convergenceRenorm==TRUE && renormNIter>0)
{
.MODEL_outputText(outputText=!quietly,paste0('\nConvergence reached in ',renormNIter,' iterations.\n...RENORM OK\n'))
#export results
tmpL=list()
for (idxI in 1:length(INSTRUMENT))
{
tmpL[[INSTRUMENT[idxI]]]=TSERIES(SINSTR_[idxI,],START=c(TSRANGE[1],TSRANGE[2]),FREQ=frequency,avoidCompliance=TRUE)
}
model$renorm$INSTRUMENT=tmpL
#export data used in convergence (before restore)
model$renorm$modelData=model$modelData
model$renorm$ConstantAdjustment=ConstantAdjustment
break
}
.MODEL_outputText(outputText=!quietly,paste0('\nRENORM(): iteration #',renormNIter+1,'\n'))
#get current INSTRUMENT
for (idxI in 1:length(INSTRUMENT))
{
tmpI=INSTRUMENT[idxI]
if (tmpI %in% model$vexog)
{
#instrument is vexog so get data from model$data
INSTRUMENT_CURRENT[[tmpI]]=model$modelData[[tmpI]]
} else if (tmpI %in% model$vendog)
{
INSTRUMENT_CURRENT[[tmpI]]=ConstantAdjustment[[tmpI]]
}
#project in TSRANGE
INSTRUMENT_CURRENT[[tmpI]]=TSPROJECT(INSTRUMENT_CURRENT[[tmpI]],TSRANGE=TSRANGE,EXTEND=TRUE,avoidCompliance=TRUE)
xxx_[idxI,]=coredata(INSTRUMENT_CURRENT[[tmpI]])
}
INSTR_=c(xxx_)
tryCatch({
# multmatrix -------------------------------------------------------------------------------
#calc MM
model=MULTMATRIX(model=model,
simAlgo=simAlgo,
RENORM=TRUE,
TSRANGE=TSRANGE,
simType=simType,
simConvergence=simConvergence,
simIterLimit=simIterLimit,
ZeroErrorAC=ZeroErrorAC,
BackFill=BackFill,
Exogenize=Exogenize,
ConstantAdjustment=ConstantAdjustment,
verbose=verbose,
verboseSincePeriod=verboseSincePeriod,
verboseVars=verboseVars,
TARGET=names(TARGET),
INSTRUMENT=INSTRUMENT,
MM_SHOCK=MM_SHOCK,
quietly=quietlyMULTMATRIX,
JACOBIAN_SHOCK=JACOBIAN_SHOCK,
JacobianDrop=JacobianDrop,
forceForwardLooking=forceForwardLooking,
avoidCompliance=TRUE,
...)
}, error=function(err){
stop(paste0('\nRENORM(): error in iteration #',renormNIter+1,': ',err$message))
})
#get simulated TARGETs
for (idxT in 1:length(TARGET))
{
#in MULTMAT we have multiple simulation column results, so [,1]
xxx_[idxT,]=coredata(TSPROJECT(model$simulation[[names(TARGET)[idxT]]],TSRANGE=TSRANGE,avoidCompliance=TRUE))
}
TARG0_=c((xxx_))
#calc delta in TARGET
NTARG_ =TARG_-TARG0_
#get adjusted INSTRUMENTs
tryCatch({
INSTR_=as.vector(INSTR_+solve(model$MultiplierMatrix,
tol=tol) %*% NTARG_)
},error=function(err){
stop(paste0('RENORM(): cannot invert multipliers matrix in iteration #',renormNIter+1,': ',err$message))
})
SINSTR_=matrix(INSTR_,nrow=length(INSTRUMENT),ncol=TSRANGEextension)
#update adjusted INSTRUMENTs
for (idxI in 1:length(INSTRUMENT))
{
tmpI=INSTRUMENT[idxI]
if (tmpI %in% model$vexog)
{
#instrument is vexog so append new data to model$data
model$modelData[[tmpI]][[TSRANGE[1],TSRANGE[2]]]=SINSTR_[idxI,]
} else if (tmpI %in% model$vendog)
{
ConstantAdjustment[[tmpI]][[TSRANGE[1],TSRANGE[2]]]=SINSTR_[idxI,]
}
}
}#end main cycle
#restore model data
for (idxI in 1:length(INSTRUMENT))
{
tmpI=INSTRUMENT[idxI]
if (tmpI %in% model$vexog)
{
#instrument is vexog so restore data to model$data
model$modelData[[tmpI]]=INSTRUMENT_ORIGINAL[[tmpI]]
} else if (tmpI %in% model$vendog)
{
#instrument is vendog so restore data to CA
ConstantAdjustment[[tmpI]]=INSTRUMENT_ORIGINAL[[tmpI]]
}
}
#export achieved TARGET
tmpL=list()
for (idxN in names(TARGET))
{
#...probably TSPROJECT not required
tmpL[[idxN]]=TSPROJECT(model$simulation[[idxN]],TSRANGE=TSRANGE,EXTEND=TRUE,avoidCompliance=TRUE)
}
model$renorm$TARGET=tmpL
#export renorm parameters
model$renorm[['__RENORM_PARAMETERS__']]$TSRANGE=TSRANGE
model$renorm[['__RENORM_PARAMETERS__']]$TARGET=TARGET
model$renorm[['__RENORM_PARAMETERS__']]$INSTRUMENT=INSTRUMENT
return(model)
}
# MULTMATRIX code --------------------------------------------------------------
MULTMATRIX <- function(model=NULL,
simAlgo='GAUSS-SEIDEL',
TSRANGE=NULL,
simType='DYNAMIC',
simConvergence=0.01,
simIterLimit=100,
ZeroErrorAC=FALSE,
BackFill=0,
Exogenize=NULL,
ConstantAdjustment=NULL,
verbose=FALSE,
verboseSincePeriod=0,
verboseVars=NULL,
TARGET=NULL,
INSTRUMENT=NULL,
MM_SHOCK=0.00001,
quietly=FALSE,
JACOBIAN_SHOCK=1e-4,
JacobianDrop=NULL,
forceForwardLooking=FALSE,
avoidCompliance=FALSE,
...)
{
tryCatch({
model=SIMULATE(model=model,
simAlgo=simAlgo,
TSRANGE=TSRANGE,
simType=simType,
simConvergence=simConvergence,
simIterLimit=simIterLimit,
ZeroErrorAC=ZeroErrorAC,
BackFill=BackFill,
Exogenize=Exogenize,
ConstantAdjustment=ConstantAdjustment,
verbose=verbose,
verboseSincePeriod=verboseSincePeriod,
verboseVars=verboseVars,
MULTMATRIX=TRUE,
TARGET=TARGET,
INSTRUMENT=INSTRUMENT,
MM_SHOCK=MM_SHOCK,
quietly=quietly,
JACOBIAN_SHOCK=JACOBIAN_SHOCK,
JacobianDrop=JacobianDrop,
forceForwardLooking=forceForwardLooking,
avoidCompliance=avoidCompliance,
...)
}, error=function(err){
stop('\n',err$message)
})
return(model)
}
# OPTIMIZE code ----------------------------------------------------------------
OPTIMIZE <- function(model=NULL,
simAlgo='GAUSS-SEIDEL',
TSRANGE=NULL,
simType='DYNAMIC',
simConvergence=0.01,
simIterLimit=100,
ZeroErrorAC=FALSE,
BackFill=0,
Exogenize=NULL,
ConstantAdjustment=NULL,
verbose=FALSE,
verboseSincePeriod=0,
verboseVars=NULL,
StochReplica=100,
StochSeed=NULL,
OptimizeBounds=NULL,
OptimizeRestrictions=NULL,
OptimizeFunctions=NULL,
quietly=FALSE,
RESCHECKeqList=NULL,
JACOBIAN_SHOCK=1e-4,
JacobianDrop=NULL,
forceForwardLooking=FALSE,
avoidCompliance=FALSE,
...)
{
tryCatch({
model=SIMULATE(model=model,
simAlgo=simAlgo,
OPTIMIZE=TRUE,
TSRANGE=TSRANGE,
simType=simType,
simConvergence=simConvergence,
simIterLimit=simIterLimit,
ZeroErrorAC=ZeroErrorAC,
BackFill=BackFill,
Exogenize=Exogenize,
ConstantAdjustment=ConstantAdjustment,
verbose=verbose,
verboseSincePeriod=verboseSincePeriod,
verboseVars=verboseVars,
StochReplica=StochReplica,
StochSeed=StochSeed,
OptimizeBounds=OptimizeBounds,
OptimizeRestrictions=OptimizeRestrictions,
OptimizeFunctions=OptimizeFunctions,
quietly=quietly,
RESCHECKeqList=RESCHECKeqList,
JACOBIAN_SHOCK=JACOBIAN_SHOCK,
JacobianDrop=JacobianDrop,
forceForwardLooking=forceForwardLooking,
avoidCompliance=avoidCompliance,
...)
}, error=function(err){
stop('\n',err$message)
})
return(model)
}
# STOCHSIMULATE code -----------------------------------------------------------
STOCHSIMULATE <- function(model=NULL,
simAlgo='GAUSS-SEIDEL',
TSRANGE=NULL,
simType='DYNAMIC',
simConvergence=0.01,
simIterLimit=100,
ZeroErrorAC=FALSE,
BackFill=0,
Exogenize=NULL,
ConstantAdjustment=NULL,
verbose=FALSE,
verboseSincePeriod=0,
verboseVars=NULL,
StochStructure=NULL,
StochReplica=100,
StochSeed=NULL,
quietly=FALSE,
RESCHECKeqList=NULL,
JACOBIAN_SHOCK=1e-4,
JacobianDrop=NULL,
forceForwardLooking=FALSE,
avoidCompliance=FALSE,
...)
{
tryCatch({
model=SIMULATE(model=model,
simAlgo=simAlgo,
STOCHSIMULATE=TRUE,
TSRANGE=TSRANGE,
simType=simType,
simConvergence=simConvergence,
simIterLimit=simIterLimit,
ZeroErrorAC=ZeroErrorAC,
BackFill=BackFill,
Exogenize=Exogenize,
ConstantAdjustment=ConstantAdjustment,
verbose=verbose,
verboseSincePeriod=verboseSincePeriod,
verboseVars=verboseVars,
StochStructure=StochStructure,
StochReplica=StochReplica,
StochSeed=StochSeed,
quietly=quietly,
RESCHECKeqList=RESCHECKeqList,
JACOBIAN_SHOCK=JACOBIAN_SHOCK,
JacobianDrop=JacobianDrop,
forceForwardLooking=forceForwardLooking,
avoidCompliance=avoidCompliance,
...)
}, error=function(err){
stop('\n',err$message)
})
return(model)
}
# SIMULATE code ----------------------------------------------------------------
SIMULATE <- function(model=NULL,
simAlgo='GAUSS-SEIDEL',
TSRANGE=NULL,
simType='DYNAMIC',
simConvergence=0.01,
simIterLimit=100,
ZeroErrorAC=FALSE,
BackFill=0,
Exogenize=NULL,
ConstantAdjustment=NULL,
verbose=FALSE,
verboseSincePeriod=0,
verboseVars=NULL,
MULTMATRIX=FALSE,
RENORM=FALSE,
TARGET=NULL,
INSTRUMENT=NULL,
MM_SHOCK=0.00001,
STOCHSIMULATE=FALSE,
StochStructure=NULL,
StochReplica=100,
StochSeed=NULL,
OPTIMIZE=FALSE,
OptimizeBounds=NULL,
OptimizeRestrictions=NULL,
OptimizeFunctions=NULL,
quietly=FALSE,
RESCHECKeqList=NULL,
JACOBIAN_SHOCK=1e-4,
JacobianDrop=NULL,
forceForwardLooking=FALSE,
avoidCompliance=FALSE,
...)
{
if (is.null(model) ) stop(callerName,'NULL model.')
if (is.null(class( model )) || !(inherits( model ,'BIMETS_MODEL')) )
stop(callerName,'model must be instance of "BIMETS_MODEL" class.')
#parent function call name
callerName='SIMULATE'
if (! is.logical(MULTMATRIX) || is.na(MULTMATRIX)) stop('SIMULATE(): "MULTMATRIX" must be logical.')
if (! is.logical(RENORM) || is.na(RENORM)) stop('SIMULATE(): "RENORM" must be logical.')
if (! is.logical(STOCHSIMULATE) || is.na(STOCHSIMULATE)) stop('SIMULATE(): "STOCHSIMULATE" must be logical.')
if (! is.logical(OPTIMIZE) || is.na(OPTIMIZE)) stop('SIMULATE(): "OPTIMIZE" must be logical.')
if (MULTMATRIX)
{
if (RENORM)
{
callerName='RENORM'
} else
{
callerName='MULTMATRIX'
}
}
if (STOCHSIMULATE) callerName='STOCHSIMULATE'
if (OPTIMIZE) callerName='OPTIMIZE'
.checkModelBimetsVersion(model, callerName)
callerName=paste0(callerName,'(): ')
if (is.null(TSRANGE) ) stop(callerName,'"TSRANGE" must be defined.')
if (! ( is.numeric(simIterLimit) && (simIterLimit > 0) ))
stop(callerName,'"simIterLimit" must be a positive number.')
if (! ( is.numeric(BackFill) && (BackFill >= 0) && (BackFill %% 1 == 0) ))
stop(callerName,'"BackFill" must be zero or a positive integer number.')
if (! ( is.numeric(simConvergence) && (simConvergence > 0) ))
stop(callerName,'"simConvergence" must be a positive number.')
if (! is.character(simType) || ! toupper(simType) %in% c('DYNAMIC','STATIC','RESCHECK','FORECAST'))
stop(callerName,'"simType" must be "DYNAMIC", "STATIC", "FORECAST" or "RESCHECK"')
simType=toupper(simType)
if (! is.character(simAlgo) || ! toupper(simAlgo) %in% c('GAUSS-SEIDEL', 'NEWTON','FULLNEWTON'))
stop(callerName,'"simAlgo" must be "GAUSS-SEIDEL", "NEWTON" or "FULLNEWTON".')
if (simAlgo=='FULLNEWTON' && MULTMATRIX==FALSE && RENORM==FALSE && OPTIMIZE==FALSE && STOCHSIMULATE==FALSE)
stop(callerName,'"FULLNEWTON" algorithm cannot be used in SIMULATE procedure. Please switch to "NETWON" or "GAUSS-SEIDEL".')
simType=toupper(simType)
if (! (is.numeric(MM_SHOCK) && is.finite(MM_SHOCK) && MM_SHOCK>0))
stop(callerName,'"MM_SHOCK" must be numeric and positive.')
if (! (is.numeric(JACOBIAN_SHOCK) && is.finite(JACOBIAN_SHOCK) && JACOBIAN_SHOCK>0))
stop(callerName,'"JACOBIAN_SHOCK" must be numeric and positive.')
if (! is.logical(verbose) || is.na(verbose)) stop(callerName,'"verbose" must be logical.')
if (! is.logical(forceForwardLooking) || is.na(forceForwardLooking)) stop(callerName,'"forceForwardLooking" must be logical.')
if (! is.logical(quietly) || is.na(quietly)) stop(callerName,'"quietly" must be logical.')
if (MULTMATRIX && simType=='RESCHECK')
stop(callerName,'a "RESCHECK" simulation is not allowed in a MULTMATRIX() operation.')
if (! (
is.numeric(verboseSincePeriod) && (verboseSincePeriod >= 0)
) ) stop(callerName,'"verboseSincePeriod" must be a positive number.')
if (MULTMATRIX && STOCHSIMULATE) stop(callerName,'if "STOCHSIMULATE" is TRUE then "MULTMATRIX" must be FALSE.')
if (OPTIMIZE && STOCHSIMULATE) stop(callerName,'if "STOCHSIMULATE" is TRUE then "OPTIMIZE" must be FALSE.')
if (MULTMATRIX && OPTIMIZE) stop(callerName,'if "OPTIMIZE" is TRUE then "MULTMATRIX" must be FALSE.')
if (verbose) quietly=FALSE
if (! avoidCompliance)
{
#check model data
tryCatch({
.CHECK_MODEL_DATA(model,showWarnings=verbose,callerName)
},error=function(e){stop(callerName,'',e$message)})
}
#get regex definitions
regExDefs=.RegExGlobalDefinition()
reservedKeyw=regExDefs$reservedKeyw
symOnEqCleaner=regExDefs$symOnEqCleaner
symOnIfCleaner=regExDefs$symOnIfCleaner
allowedCharOnName=regExDefs$allowedCharOnName
allowedCharOnNameToken=regExDefs$allowedCharOnNameToken
charsOnNumbs=regExDefs$charsOnNumbs
charsOnNumWithSign=regExDefs$charsOnNumWithSign
strongCharOnNumbs=regExDefs$strongCharOnNumbs
strongCharOnNumbsWithSign=regExDefs$strongCharOnNumbsWithSign
allowedLhsEQfuns=regExDefs$allowedLhsEQfuns
allowedLhsEQfunsPub=regExDefs$allowedLhsEQfunsPub
#main tryCatch for compliance speedup
tryCatch({
#get compliance status
complianceStatus=getBIMETSconf('BIMETS_CONF_NOC')
setBIMETSconf('BIMETS_CONF_NOC',TRUE, suppressOutput=TRUE)
#get data frequency
frequency=frequency(model$modelData[[1]])
#check TSRANGE is consistent
if (! is.null(TSRANGE)) {
tryCatch({
if (! ( is.numeric(TSRANGE) && length(TSRANGE)==4 &&
.isCompliantYP(c(TSRANGE[1],TSRANGE[2]),frequency) &&
.isCompliantYP(c(TSRANGE[3],TSRANGE[4]),frequency) &&
NUMPERIOD(c(TSRANGE[1],TSRANGE[2]),c(TSRANGE[3],TSRANGE[4]),frequency)>=0
)
) stop()
},error=function(e) {stop(callerName,'syntax error in TSRANGE: ',e$message)})
}
#check exoginanda vendog exists in model
if (! is.null(Exogenize))
{
if (! is.list(Exogenize) )
stop(callerName,'"Exogenize" must be a list built of endogenous variables as names and related TSRANGE as items.')
if (length(names(Exogenize)) != length(unique(names(Exogenize)))) stop(callerName,'there are duplicated names in "Exogenize".')
if (length(base::setdiff(names(Exogenize),model$vendog)) >0)
stop(callerName,'request to exogenize "',
paste0(base::setdiff(names(Exogenize),model$vendog),collapse=', '),
'", not endogenous variable(s) of the model.')
}
#check CA vendog exists in model
if (! is.null(ConstantAdjustment))
{
if (! is.list(ConstantAdjustment) )
stop(callerName,'"ConstantAdjustment" must be a list built of endogenous variables as names and related time series as items.')
if (length(base::setdiff(names(ConstantAdjustment),model$vendog)) >0)
stop(callerName,'request to add a constant adjustment to "',
paste0(base::setdiff(names(ConstantAdjustment),model$vendog),collapse=', '),
'", not endogenous variable(s) of the model.')
}
#check RESCHECKeqList vendog exists in model
if (! is.null(RESCHECKeqList))
{
if (OPTIMIZE)
stop(callerName,'"RESCHECKeqList" in not available in a OPTIMIZE operation.')
if (simType!='RESCHECK')
{
.MODEL_outputText(outputText=!quietly,paste0(callerName,'simulation of type "',simType,'" requested. "RESCHECKeqList" will be set to NULL.\n'))
RESCHECKeqList=NULL
} else
{
if (! is.character(RESCHECKeqList) )
stop(callerName,'"RESCHECKeqList" must be a character array built of endogenous variables names.')
if (length(base::setdiff((RESCHECKeqList),model$vendog)) >0)
stop(callerName,'request to RESCHECK the following "',
paste0(base::setdiff((RESCHECKeqList),model$vendog),collapse=', '),
'", not endogenous variable(s) of the model.')
if (length(Exogenize)>0)
for (idxEL in names(Exogenize))
{
if (! idxEL %in% RESCHECKeqList)
{
.MODEL_outputText(outputText=!quietly,paste0(callerName,'warning, request to exogenize "',idxEL,'", but it is not in "RESCHECKeqList". It will be removed from "Exogenize" list.\n'))
Exogenize[[idxEL]]=NULL
}
}
if (length(ConstantAdjustment)>0)
for (idxCA in names(ConstantAdjustment))
{
if (! idxCA %in% RESCHECKeqList)
{
.MODEL_outputText(outputText=!quietly,paste0(callerName,'warning, constant adjustment "',idxCA,'" is not in "RESCHECKeqList". It will be removed from "ConstantAdjustment" list.\n'))
ConstantAdjustment[[idxCA]]=NULL
}
}
}
}
#check (Exogenize) is consistent
if (length(Exogenize)>0)
for (idxEL in 1:length(Exogenize))
{
if (is.logical(Exogenize[[idxEL]]) && ! is.na(Exogenize[[idxEL]]))
{
if (Exogenize[[idxEL]]!=TRUE)
stop(callerName,'syntax error in Exogenize TSRANGE of "',
names(Exogenize)[idxEL],'".')
#set full TSRANGE if Expogenize is TRUE
Exogenize[[idxEL]]=TSRANGE
next
}
#check provided TSRANGE
tryCatch({
tmpTSRANGE=Exogenize[[idxEL]]
if (! ( is.numeric(tmpTSRANGE) && length(tmpTSRANGE)==4 &&
.isCompliantYP(c(tmpTSRANGE[1],tmpTSRANGE[2]),frequency) &&
.isCompliantYP(c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency) &&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency)>=0
)
) stop()
},error=function(e) {stop(callerName,'syntax error in Exogenize TSRANGE of "',
names(Exogenize)[idxEL],'". ',e$message)
})
}
#sim steps count
simSteps=NUMPERIOD(TSRANGE[1:2],TSRANGE[3:4],frequency)+1
#check (ConstantAdjustment) is consistent
if (length(ConstantAdjustment)>0)
for (idxCA in 1:length(ConstantAdjustment))
{
if (! is.bimets(ConstantAdjustment[[idxCA]]))
stop(callerName,'"ConstantAdjustment" must be a list of BIMETS time series: "',names(ConstantAdjustment)[idxCA],'" time series is not compliant.')
if (frequency(ConstantAdjustment[[idxCA]])!=frequency(model$modelData[[1]]))
stop(callerName,'time series must have the same frequency. Check constant adjustment time series "',names(ConstantAdjustment)[idxCA],'".')
if (verbose && any(! is.finite(coredata(ConstantAdjustment[[idxCA]])))) .MODEL_outputText(outputText = !quietly,callerName,'warning, there are undefined values in constant adjustment time series "',names(ConstantAdjustment)[idxCA],'".\n',sep='')
}
#check intersection between Simulation TSRANGE and Exogenize TSRANGE
#remove items whose exogenation TSRANGE is outside Simulation TSRANGE
idxToBeRemoved=c()
if (length(Exogenize)>0)
for (idxEL in 1:length(Exogenize))
{
tmpTSRANGE=Exogenize[[idxEL]]
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
idxToBeRemoved=c(idxToBeRemoved,idxEL)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, exogenize TSRANGE of "',names(Exogenize)[idxEL],'" does not intersect with simulation TSRANGE.\n'))
}
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
idxToBeRemoved=c(idxToBeRemoved,idxEL)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, exogenize TSRANGE of "',names(Exogenize)[idxEL],'" does not intersect with simulation TSRANGE.\n'))
}
}
}
#remove out of range exogenizations
if (length(idxToBeRemoved)>0) Exogenize=Exogenize[-idxToBeRemoved]
if (length(Exogenize)>0)
for (idxEL in 1:length(Exogenize))
{
#cut exogenization range up to sim start
if (NUMPERIOD(c(Exogenize[[idxEL]][1],Exogenize[[idxEL]][2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, exogenize TSRANGE of "',names(Exogenize)[idxEL],'" starts before the simulation TSRANGE.\n'))
Exogenize[[idxEL]][1]=TSRANGE[1]
Exogenize[[idxEL]][2]=TSRANGE[2]
}
#cut exogenization range back to sim end
if (NUMPERIOD(c(Exogenize[[idxEL]][3],Exogenize[[idxEL]][4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, exogenize TSRANGE of "',names(Exogenize)[idxEL],'" ends after the simulation TSRANGE.\n'))
Exogenize[[idxEL]][3]=TSRANGE[3]
Exogenize[[idxEL]][4]=TSRANGE[4]
}
}
#check TARGET if MM is T
if (MULTMATRIX==TRUE && (is.null(TARGET) || length(TARGET)==0) )
stop(callerName,'impact multipliers matrix requested but TARGET names are NULL.')
if (MULTMATRIX==TRUE && length(TARGET)>0)
if (length(base::setdiff(TARGET,model$vendog))>0)
stop(callerName,'TARGET variables "',paste0(base::setdiff(TARGET,model$vendog),collapse=', ') ,
'" are not endogenous variables of the model.')
#check INSTRUMENT if MM is T
if (MULTMATRIX==TRUE && (is.null(INSTRUMENT) || length(INSTRUMENT)==0) )
stop(callerName,'impact multipliers matrix requested but INSTRUMENT names are NULL.')
#vendog variables that are used as instruments
instrumentVendogs=NULL
if (anyDuplicated(INSTRUMENT)>0) stop(callerName,'there are duplicated entries on INSTRUMENT namelist: "',INSTRUMENT[anyDuplicated(INSTRUMENT)],'".')
if (anyDuplicated(TARGET)>0) stop(callerName,'there are duplicated entries on TARGET namelist: "',TARGET[anyDuplicated(TARGET)],'".')
if (MULTMATRIX==TRUE && length(INSTRUMENT)>0)
{
instrumentVendogs=base::intersect(INSTRUMENT,model$vendog)
for (idxT in 1:length(INSTRUMENT))
{
#if instrument is endogenous then we use related add-factor
if (INSTRUMENT[idxT] %in% model$vendog)
{
INSTRUMENT[idxT]=paste0(INSTRUMENT[idxT],'__ADDFACTOR')
next
}
#check tragets in vendog list
if (! INSTRUMENT[idxT] %in% model$vexog) stop(callerName,'INSTRUMENT variable "',INSTRUMENT[idxT] ,
'" is not a model variable.')
}
}
#set replica if MULTMATRIX selected
if (MULTMATRIX==TRUE)
{
#in lead case replica count is the same
replica=length(INSTRUMENT)*simSteps+1
} else replica=1
# local var localE speedup -----------------------------------------------
#a local env will contains model time series in assign(), get() and eval()
#it will speed up calculus
localE=new.env()
#we need at least 1 lag in order to start simulation in case simType=FORECAST
model_max_lag=max(model$max_lag,1)
model_max_lag_1=model_max_lag+1
model_max_lead=model$max_lead
#use local var for speedup
model_vendog=model$vendog
model_vexog=model$vexog
length_model_vexog=length(model_vexog)
model_names_behavioral=names(model$behaviorals)
model_names_identity=names(model$identities)
model_fullComponentList=c(model$vendog,model$vexog)
model_vpre=model$vpre
length_model_vpre=length(model_vpre)
length_model_vblocks=length(model$vblocks)
model_vblocks=model$vblocks
model_vsim=list()
model_vpost=list()
model_vfeed=list()
length_model_vsim=c()
length_model_vpost=c()
length_model_vfeed=c()
if (length(ConstantAdjustment)>0)
CA_names=paste0(names(ConstantAdjustment),'__ADDFACTOR')
if (length(instrumentVendogs)>0)
instrum_names=paste0(instrumentVendogs,'__ADDFACTOR')
# check STOCHSIMULATE ------------------------------------------------------------
if (STOCHSIMULATE)
{
#check arguments
if (!is.list(StochStructure) || is.null(names(StochStructure)))
stop(callerName,'"StochStructure" must be a named list.')
if (length(names(StochStructure)) != length(unique(names(StochStructure))))
stop(callerName,'there are duplicated names in "StochStructure"')
for (idxI in 1:length(StochStructure))
{
idxN=names(StochStructure)[idxI]
if (! idxN %in% c(model$vendog,model$vexog))
stop(callerName,'"StochStructure" has a named element "',idxN,'" that is not a model variable.')
if (! is.list(StochStructure[[idxN]])
|| is.null(names(StochStructure[[idxN]]))
|| length(StochStructure[[idxN]])!=3
|| all(sort(names(StochStructure[[idxN]])) != c('PARS','TSRANGE','TYPE')))
stop(callerName,'"StochStructure$',idxN,'" must be a named list built of the following 3 components: TSRANGE, TYPE, PARS.')
if (length(StochStructure[[idxN]]$TSRANGE)==1 && is.logical(StochStructure[[idxN]]$TSRANGE) && ! is.na(StochStructure[[idxN]]$TSRANGE))
{
if (StochStructure[[idxN]]$TSRANGE!=TRUE)
stop(callerName,'"StochStructure$',idxN,'$TSRANGE" must be TRUE or a 4 element integer array.')
#set full TSRANGE if StochStructure$idxN$TSRANGE is TRUE
StochStructure[[idxN]]$TSRANGE=TSRANGE
} else
{
#check TSRANGE
tryCatch({
tmpTSRANGE=StochStructure[[idxN]]$TSRANGE
if (! ( is.numeric(tmpTSRANGE) && length(tmpTSRANGE)==4 &&
.isCompliantYP(c(tmpTSRANGE[1],tmpTSRANGE[2]),frequency) &&
.isCompliantYP(c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency) &&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency)>=0
)
) stop()
},error=function(e) {stop(callerName,'syntax error in "StochStructure$',idxN,'$TSRANGE". ',e$message)
})
}
}
idxToBeRemoved=c()
for (idxN in 1:length(StochStructure))
{
elemName=names(StochStructure)[idxN]
tmpTSRANGE=StochStructure[[idxN]]$TSRANGE
#check intersection between StochStructure TSRANGE and Simulation TSRANGE
#remove items whose TSRANGE is outside Simulation TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "StochStructure$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "StochStructure$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
}
#remove unused stoch perturbation
if (length(idxToBeRemoved)>0) StochStructure=StochStructure[-idxToBeRemoved]
#project stoch TSRANGE in sim TSRANGE
if (length(StochStructure)>0)
{ for (idxN in 1:length(StochStructure))
{
tmpTSRANGE=StochStructure[[idxN]]$TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "StochStructure$',names(StochStructure)[idxN],'$TSRANGE" starts before the simulation TSRANGE\n'))
tmpTSRANGE[1]=TSRANGE[1]
tmpTSRANGE[2]=TSRANGE[2]
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "StochStructure$',names(StochStructure)[idxN],'$TSRANGE" ends after the simulation TSRANGE\n'))
tmpTSRANGE[3]=TSRANGE[3]
tmpTSRANGE[4]=TSRANGE[4]
}
StochStructure[[idxN]]$TSRANGE=tmpTSRANGE
}
for (idxI in 1:length(StochStructure))
{
idxN=names(StochStructure)[idxI]
if (! is.character(StochStructure[[idxN]]$TYPE)
|| ! StochStructure[[idxN]]$TYPE %in% c('NORM','UNIF','MATRIX')
) stop(callerName,'"StochStructure$',idxN,'$TYPE" must be NORM or UNIF or MATRIX.')
if (StochStructure[[idxN]]$TYPE=='UNIF'
|| StochStructure[[idxN]]$TYPE=='NORM')
{
if (any(is.null(StochStructure[[idxN]]$PARS))
|| any(! is.finite(StochStructure[[idxN]]$PARS))
|| length(StochStructure[[idxN]]$PARS) !=2)
stop(callerName,'"StochStructure$',idxN,'$PARS" must be a 2 elements finite numerical array.')
}
if (StochStructure[[idxN]]$TYPE=='MATRIX')
{
if (! is.matrix(StochStructure[[idxN]]$PARS) || !(all(is.finite(StochStructure[[idxN]]$PARS))))
stop(callerName,'"StochStructure$',idxN,'$PARS" must be a finite matrix.')
}
}
}
if (is.null(StochReplica)
|| ! is.finite(StochReplica)
|| StochReplica < 1
|| StochReplica %% 1 != 0 )
stop(callerName,'"StochReplica" must be a positive integer.')
if (! is.null(StochSeed))
{
if(! is.finite(StochSeed))
stop(callerName,'"StochSeed" must be a finite number.')
#set provided seed into the random generator
set.seed(StochSeed)
}
#set replica if STOCHSIMULATE selected
#(first column is unperturbed model so we add one)
replica=StochReplica+1
}#end if STOCHSIMULATE
# check OPTIMIZE ------------------------------------------------------------
if (OPTIMIZE)
{
if (is.null(StochReplica)
|| ! is.finite(StochReplica)
|| StochReplica < 1
|| StochReplica %% 1 != 0 )
stop(callerName,'"StochReplica" must be a positive integer.')
if (! is.null(StochSeed))
{
if(! is.finite(StochSeed))
stop(callerName,'"StochSeed" must be a finite number.')
#set provided seed into the random generator
set.seed(StochSeed)
}
#set replica if OPTIMIZE selected
#(first column id unperturbed model so we add plus one)
replica=StochReplica+1
#check argument OptimizeBounds
if (!is.list(OptimizeBounds) || is.null(names(OptimizeBounds)))
stop(callerName,'"OptimizeBounds" must be a named list.')
if (length(names(OptimizeBounds)) != length(unique(names(OptimizeBounds))))
stop(callerName,'there are duplicated names in "OptimizeBounds".')
for (idxI in 1:length(OptimizeBounds))
{
idxN=names(OptimizeBounds)[idxI]
if (! idxN %in% model_fullComponentList)
stop(callerName,'"OptimizeBounds" has a named element "',idxN,'" that is not a model variable.')
if (! is.list(OptimizeBounds[[idxN]])
|| is.null(names(OptimizeBounds[[idxN]]))
|| length(OptimizeBounds[[idxN]])!=2
|| all(sort(names(OptimizeBounds[[idxN]])) != c('BOUNDS','TSRANGE')))
stop(callerName,'"OptimizeBounds$',idxN,'" must be a named list built of the following 2 components: TSRANGE, BOUNDS')
if (is.logical(OptimizeBounds[[idxN]]$TSRANGE) && ! is.na(OptimizeBounds[[idxN]]$TSRANGE))
{
if (OptimizeBounds[[idxN]]$TSRANGE!=TRUE)
stop(callerName,'"OptimizeBounds$',idxN,'$TSRANGE" must be TRUE or a 4 element integer array.')
#set full TSRANGE if OptimizeBounds$idxN$TSRANGE is TRUE
OptimizeBounds[[idxN]]$TSRANGE=TSRANGE
} else
{
#check TSRANGE
tryCatch({
tmpTSRANGE=OptimizeBounds[[idxN]]$TSRANGE
if (! ( is.numeric(tmpTSRANGE) && length(tmpTSRANGE)==4 &&
.isCompliantYP(c(tmpTSRANGE[1],tmpTSRANGE[2]),frequency) &&
.isCompliantYP(c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency) &&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency)>=0
)
) stop()
},error=function(e) {stop(callerName,'syntax error in "OptimizeBounds$',idxN,'$TSRANGE". ',e$message)
})
}
}
idxToBeRemoved=c()
for (idxN in 1:length(OptimizeBounds))
{
elemName=names(OptimizeBounds)[idxN]
tmpTSRANGE=OptimizeBounds[[idxN]]$TSRANGE
#check intersection between OptimizeBounds TSRANGE and Simulation TSRANGE
#remove items whose TSRANGE is outside Simulation TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeBounds$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeBounds$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
}
if (length(idxToBeRemoved)>0) OptimizeBounds=OptimizeBounds[-idxToBeRemoved]
if (length(OptimizeBounds)>0)
{
for (idxN in 1:length(OptimizeBounds))
{
tmpTSRANGE=OptimizeBounds[[idxN]]$TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeBounds$',names(OptimizeBounds)[idxN],'$TSRANGE" starts before the simulation TSRANGE.\n'))
tmpTSRANGE[1]=TSRANGE[1]
tmpTSRANGE[2]=TSRANGE[2]
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeBounds$',names(OptimizeBounds)[idxN],'$TSRANGE" ends after the simulation TSRANGE.\n'))
tmpTSRANGE[3]=TSRANGE[3]
tmpTSRANGE[4]=TSRANGE[4]
}
OptimizeBounds[[idxN]]$TSRANGE=tmpTSRANGE
}
for (idxI in 1:length(OptimizeBounds))
{
idxN=names(OptimizeBounds)[idxI]
if (any(is.null(OptimizeBounds[[idxN]]$BOUNDS))
|| any(! is.finite(OptimizeBounds[[idxN]]$BOUNDS))
|| length(OptimizeBounds[[idxN]]$BOUNDS) !=2)
stop(callerName,'"OptimizeBounds$',idxN,'$BOUNDS" must be a 2 elements finite numerical array.')
if (OptimizeBounds[[idxN]]$BOUNDS[1] >= OptimizeBounds[[idxN]]$BOUNDS[2])
stop(callerName,'"OptimizeBounds$',idxN,'$BOUNDS[2]" must be greater than "OptimizeBounds$',idxN,'$BOUNDS[1]".')
}
} else {
stop(callerName,'"OptimizeBounds" are null in the simulation TSRANGE.')
}
# end check OptimizeBounds
#check argument OptimizeRestrictions
if (! is.null(OptimizeRestrictions))
{
if (!is.list(OptimizeRestrictions) || is.null(names(OptimizeRestrictions))) stop(callerName,'"OptimizeRestrictions" must be a named list.')
if (length(names(OptimizeRestrictions)) != length(unique(names(OptimizeRestrictions)))) stop(callerName,'there are duplicated names in "OptimizeRestrictions".')
for (idxI in 1:length(OptimizeRestrictions))
{
idxN=names(OptimizeRestrictions)[idxI]
if (! is.list(OptimizeRestrictions[[idxN]])
|| is.null(names(OptimizeRestrictions[[idxN]]))
|| length(OptimizeRestrictions[[idxN]])!=2
|| all(sort(names(OptimizeRestrictions[[idxN]])) != c('INEQUALITY','TSRANGE')))
stop(callerName,'"OptimizeRestrictions$',idxN,'" must be a named list built of the following 2 components: TSRANGE, INEQUALITY.')
if (is.logical(OptimizeRestrictions[[idxN]]$TSRANGE) && ! is.na(OptimizeRestrictions[[idxN]]$TSRANGE))
{
if (OptimizeRestrictions[[idxN]]$TSRANGE!=TRUE)
stop(callerName,'"OptimizeRestrictions$',idxN,'$TSRANGE" must be TRUE or a 4 element integer array.')
#set full TSRANGE if OptimizeRestrictions$idxN$TSRANGE is TRUE
OptimizeRestrictions[[idxN]]$TSRANGE=TSRANGE
} else
{
#check TSRANGE
tryCatch({
tmpTSRANGE=OptimizeRestrictions[[idxN]]$TSRANGE
if (! ( is.numeric(tmpTSRANGE) && length(tmpTSRANGE)==4 &&
.isCompliantYP(c(tmpTSRANGE[1],tmpTSRANGE[2]),frequency) &&
.isCompliantYP(c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency) &&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency)>=0
)
) stop()
},error=function(e) {stop(callerName,'syntax error in "OptimizeRestrictions$',idxN,'$TSRANGE". ',e$message)
})
}
}
idxToBeRemoved=c()
for (idxN in 1:length(OptimizeRestrictions))
{
elemName=names(OptimizeRestrictions)[idxN]
tmpTSRANGE=OptimizeRestrictions[[idxN]]$TSRANGE
#check intersection between OptimizeRestrictions TSRANGE and Simulation TSRANGE
#remove items whose TSRANGE is outside Simulation TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeRestrictions$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeRestrictions$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
}
if (length(idxToBeRemoved)>0) OptimizeRestrictions=OptimizeRestrictions[-idxToBeRemoved]
if (length(OptimizeRestrictions)>0)
{
for (idxN in 1:length(OptimizeRestrictions))
{
tmpTSRANGE=OptimizeRestrictions[[idxN]]$TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeRestrictions$',names(OptimizeRestrictions)[idxN],'$TSRANGE" starts before the simulation TSRANGE.\n'))
tmpTSRANGE[1]=TSRANGE[1]
tmpTSRANGE[2]=TSRANGE[2]
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeRestrictions$',names(OptimizeRestrictions)[idxN],'$TSRANGE" ends after the simulation TSRANGE.\n'))
tmpTSRANGE[3]=TSRANGE[3]
tmpTSRANGE[4]=TSRANGE[4]
}
OptimizeRestrictions[[idxN]]$TSRANGE=tmpTSRANGE
}
#check there's no overlapping in Restrictions TSRANGEs
if (length(OptimizeRestrictions)>1)
{
for (idxN in 1:(length(OptimizeRestrictions)-1))
{
for (idxM in (idxN+1):length(OptimizeRestrictions))
{
tmpTSRANGE=OptimizeRestrictions[[idxN]]$TSRANGE
tmp2TSRANGE=OptimizeRestrictions[[idxM]]$TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(tmp2TSRANGE[1],tmp2TSRANGE[2])
,frequency)<1
&&
NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(tmp2TSRANGE[3],tmp2TSRANGE[4])
,frequency)>-1)
stop(callerName,'"OptimizeRestrictions$',names(OptimizeRestrictions)[idxN],'$TSRANGE" overlaps with "OptimizeRestrictions$',names(OptimizeRestrictions)[idxM],'$TSRANGE".')
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmp2TSRANGE[1],tmp2TSRANGE[2])
,frequency)<1
&&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmp2TSRANGE[3],tmp2TSRANGE[4])
,frequency)>-1)
stop(callerName,'"OptimizeRestrictions$',names(OptimizeRestrictions)[idxN],'$TSRANGE" overlaps with "OptimizeRestrictions$',names(OptimizeRestrictions)[idxM],'$TSRANGE".')
}
}
}
for (idxI in 1:length(OptimizeRestrictions))
{
idxN=names(OptimizeRestrictions)[idxI]
if (! .checkExpression(OptimizeRestrictions[[idxN]]$INEQUALITY))
stop(callerName,'syntax error in OptimizeRestrictions$',idxN,'$INEQUALITY".')
#transform inequality raw text into suitable expression
outIE=OptimizeRestrictions[[idxN]]$INEQUALITY
#check double logical operator
if (grepl('&&',outIE)) stop(callerName,'INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'" cannot contain "&&". Please consider using the single operator "&".')
if (grepl('\\|\\|',outIE)) stop(callerName,'INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'" cannot contain "||". Please consider using the single operator "|".')
#check unknown funs names
unknownFuns=.unknownFunsNames(outIE,reservedKeyw)
if (length(unknownFuns)>0) stop(callerName,'unsupported functions in "OptimizeRestrictions$',idxN,'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
#extract components names from restriction
namesOnRestr=strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnIfCleaner,' ',outIE,ignore.case=TRUE)),'\\s+')[[1]]
#remove numbers
rmvNumOnRSIdx=c()
for (idxNamesOnR in 1:length(namesOnRestr)) {
if (length(grep(strongCharOnNumbs,namesOnRestr[idxNamesOnR]))>0)
{
rmvNumOnRSIdx=c(rmvNumOnRSIdx,idxNamesOnR)
}
}
if (length(rmvNumOnRSIdx)>0) namesOnRestr=namesOnRestr[-rmvNumOnRSIdx]
#check restriction condition is time series
if (length(namesOnRestr)==0) stop(callerName,'syntax error in INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'". Logical condition must contain time series.')
#check components name
for (idxNOR in 1:length(namesOnRestr)) {
if (length(grep(allowedCharOnName,namesOnRestr[idxNOR]))==0)
{
stop(callerName,'syntax error in INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'". The following symbol cannot be a variable name: "',namesOnRestr[idxNOR],'".')
}
}
if (any(grepl('__',namesOnRestr)))
stop(callerName,'variable names in INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'" cannot contain double underscore "__". Please change the following variable names: ',paste0(namesOnRestr[which(grepl('__',namesOnRestr))],collapse=', '))
for (idxNOR in 1:length(namesOnRestr)) {
if (! namesOnRestr[idxNOR] %in% model_fullComponentList)
{
stop(callerName,'unknown symbol in INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'". The variable "',namesOnRestr[idxNOR],'" is not a model variable.',
ifelse(! is.null(RESCHECKeqList),paste0(' Please note that RESCHECKeqList="',paste(RESCHECKeqList,collapse=', '),'"'),'')
)
}
}
outIE=gsub('<-','< -',outIE)
if (! grepl('(==|<|>|>=|<=|!=|&|\\|)',outIE))
stop(callerName,'syntax error in INEQUALITY definition "',outIE,'" in "OptimizeRestrictions$',idxN,'". No logical operators found.')
outIE=.MODEL_MOD_FUNC_NAMES(outIE)
outIE=.appendAFtoEndVars(outIE,model_vendog)
outIE=.appendIndexToVars(outIE,c(model_vexog,
paste0(model_vendog,'__ADDFACTOR'))
,'0')
#explode model funs
tempS=.explodeTSLAG(outIE)
tempS=.explodeTSLEAD(tempS$output)
tempS=.explodeTSDELTA(tempS$output)
tempS=.explodeTSDELTAP(tempS$output)
tempS=.explodeTSDELTALOG(tempS$output)
tempS=.explodeMTOT(tempS$output)
tempS=.explodeMAVE(tempS$output)
outIE=tempS$output
#stop if the inequality requires lagging time series more than model equations
tempOut=.getLowerLagAndHigherLead(outIE)
if (-tempOut$outL>model_max_lag)
stop(callerName,'"OptimizeRestrictions$',idxN,'$INEQUALITY" expression "',OptimizeRestrictions[[idxN]]$INEQUALITY,'" requires to lag time series more than model equations do.')
if (tempOut$outH>model_max_lead)
stop(callerName,'"OptimizeRestrictions$',idxN,'$INEQUALITY" expression "',OptimizeRestrictions[[idxN]]$INEQUALITY,'" requires to lead time series more than model equations do.')
#add model lag to inequality expression
outIE=.addToIndexInString(outIE, model_max_lag_1)
#append expression to list
tryCatch({
OptimizeRestrictions[[idxN]]$inExpr=parse(text=outIE)
},error=function(err) stop(callerName,'syntax error in INEQUALITY definition "',OptimizeRestrictions[[idxN]]$INEQUALITY,'" in "OptimizeRestrictions$',idxN,'".')
)
}
} else {
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeRestrictions" are null in the simulation TSRANGE.\n'))
}
}
# end check OptimizeRestrictions
#check argument OptimizeFunctions
if (!is.list(OptimizeFunctions) || is.null(names(OptimizeFunctions))) stop(callerName,'"OptimizeFunctions" must be a named list.')
if (length(names(OptimizeFunctions)) != length(unique(names(OptimizeFunctions)))) stop(callerName,'there are duplicated names in "OptimizeFunctions".')
for (idxI in 1:length(OptimizeFunctions))
{
idxN=names(OptimizeFunctions)[idxI]
if (! is.list(OptimizeFunctions[[idxN]])
|| is.null(names(OptimizeFunctions[[idxN]]))
|| length(OptimizeFunctions[[idxN]])!=2
|| all(sort(names(OptimizeFunctions[[idxN]])) != c('FUNCTION','TSRANGE')))
stop(callerName,'"OptimizeFunctions$',idxN,'" must be a named list built of the following 2 components: FUNCTION, TSRANGE.')
if (is.logical(OptimizeFunctions[[idxN]]$TSRANGE) && ! is.na(OptimizeFunctions[[idxN]]$TSRANGE))
{
if (OptimizeFunctions[[idxN]]$TSRANGE!=TRUE)
stop(callerName,'"OptimizeFunctions$',idxN,'$TSRANGE" must be TRUE or a 4 element integer array.')
#set full TSRANGE if OptimizeFunctions$idxN$TSRANGE is TRUE
OptimizeFunctions[[idxN]]$TSRANGE=TSRANGE
} else
{
#check TSRANGE
tryCatch({
tmpTSRANGE=OptimizeFunctions[[idxN]]$TSRANGE
if (! ( is.numeric(tmpTSRANGE) && length(tmpTSRANGE)==4 &&
.isCompliantYP(c(tmpTSRANGE[1],tmpTSRANGE[2]),frequency) &&
.isCompliantYP(c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency) &&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmpTSRANGE[3],tmpTSRANGE[4]),frequency)>=0)) stop()
},error=function(e) {stop(callerName,'syntax error in "OptimizeFunctions$',idxN,'$TSRANGE". ',e$message)
})
}
}
idxToBeRemoved=c()
for (idxN in 1:length(OptimizeFunctions))
{
elemName=names(OptimizeFunctions)[idxN]
tmpTSRANGE=OptimizeFunctions[[idxN]]$TSRANGE
#check intersection between OptimizeFunctions TSRANGE and Simulation TSRANGE
#remove items whose TSRANGE is outside Simulation TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeFunctions$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
idxToBeRemoved=c(idxToBeRemoved,idxN)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeFunctions$',elemName,'$TSRANGE" does not intersect with simulation TSRANGE.\n'))
}
}
}
if (length(idxToBeRemoved)>0) OptimizeFunctions=OptimizeFunctions[-idxToBeRemoved]
if (length(OptimizeFunctions)>0)
{
for (idxN in 1:length(OptimizeFunctions))
{
tmpTSRANGE=OptimizeFunctions[[idxN]]$TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(TSRANGE[1],TSRANGE[2]),frequency)>0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeFunctions$',names(OptimizeFunctions)[idxN],'$TSRANGE" starts before the simulation TSRANGE.\n'))
tmpTSRANGE[1]=TSRANGE[1]
tmpTSRANGE[2]=TSRANGE[2]
}
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(TSRANGE[3],TSRANGE[4]),frequency)<0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "OptimizeFunctions$',names(OptimizeFunctions)[idxN],'$TSRANGE" ends after the simulation TSRANGE.\n'))
tmpTSRANGE[3]=TSRANGE[3]
tmpTSRANGE[4]=TSRANGE[4]
}
OptimizeFunctions[[idxN]]$TSRANGE=tmpTSRANGE
}
#check there's no overlapping in Restrictions TSRANGEs
if (length(OptimizeFunctions)>1)
{
for (idxN in 1:(length(OptimizeFunctions)-1))
{
for (idxM in (idxN+1):length(OptimizeFunctions))
{
tmpTSRANGE=OptimizeFunctions[[idxN]]$TSRANGE
tmp2TSRANGE=OptimizeFunctions[[idxM]]$TSRANGE
if (NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(tmp2TSRANGE[1],tmp2TSRANGE[2])
,frequency)<1
&&
NUMPERIOD(c(tmpTSRANGE[3],tmpTSRANGE[4]),
c(tmp2TSRANGE[3],tmp2TSRANGE[4])
,frequency)>-1)
stop(callerName,'"OptimizeFunctions$',names(OptimizeFunctions)[idxN],'$TSRANGE" overlaps with "OptimizeFunctions$',names(OptimizeFunctions)[idxM],'$TSRANGE".')
if (NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmp2TSRANGE[1],tmp2TSRANGE[2])
,frequency)<1
&&
NUMPERIOD(c(tmpTSRANGE[1],tmpTSRANGE[2]),
c(tmp2TSRANGE[3],tmp2TSRANGE[4])
,frequency)>-1)
stop(callerName,'"OptimizeFunctions$',names(OptimizeFunctions)[idxN],'$TSRANGE" overlaps with "OptimizeFunctions$',names(OptimizeFunctions)[idxM],'$TSRANGE".')
}
}
}
for (idxI in 1:length(OptimizeFunctions))
{
idxN=names(OptimizeFunctions)[idxI]
if (! .checkExpression(OptimizeFunctions[[idxN]]$FUNCTION))
stop(callerName,'syntax error in "OptimizeFunctions$',idxN,'$FUNCTION".')
#transform fun raw text into suitable expression
outFUN=OptimizeFunctions[[idxN]]$FUNCTION
#check unknown funs names
unknownFuns=.unknownFunsNames(outFUN,reservedKeyw)
if (length(unknownFuns)>0) stop(callerName,'unsupported functions in "OptimizeFunctions$',idxN,'": ',
paste0(paste0(unknownFuns,'()'),collapse=', '))
#extract components names from restriction
namesOnFun=strsplit(gsub("^\\s+|\\s+$", "",gsub(symOnEqCleaner,' ',outFUN,ignore.case=TRUE)),'\\s+')[[1]]
#remove numbers
rmvNumOnFunIdx=c()
for (idxNamesOnF in 1:length(namesOnFun)) {
if (length(grep(strongCharOnNumbs,namesOnFun[idxNamesOnF]))>0)
{
rmvNumOnFunIdx=c(rmvNumOnFunIdx,idxNamesOnF)
}
}
if (length(rmvNumOnFunIdx)>0) namesOnFun=namesOnFun[-rmvNumOnFunIdx]
#check function is time series
if (length(namesOnFun)==0) stop(callerName,'syntax error in FUNCTION definition "',outFUN,'" in "OptimizeFunction$',idxN,'". Function definition must contain time series.')
#check components name
for (idxNOF in 1:length(namesOnFun)) {
if (length(grep(allowedCharOnName,namesOnFun[idxNOF]))==0)
{
stop(callerName,'syntax error in FUNCTION definition "',outFUN,'" in "OptimizeFunction$',idxN,'". The following symbol cannot be a variable name: "',namesOnFun[idxNOF],'".')
}
}
if (any(grepl('__',namesOnFun)))
stop(callerName,'variable names in FUNCTION definition "',outFUN,'" in "OptimizeFunction$',idxN,'" cannot contain double underscore "__". Please change the following variable names: ',paste0(namesOnFun[which(grepl('__',namesOnFun))],collapse=', '))
for (idxNOF in 1:length(namesOnFun)) {
if (! namesOnFun[idxNOF] %in% model_fullComponentList)
{
stop(callerName,'unknown symbol in FUNCTION definition "',outFUN,'" in "OptimizeFunction$',idxN,'". The variable "',namesOnFun[idxNOF],'" is not a model variable.',
ifelse(! is.null(RESCHECKeqList),paste0(' Please note that RESCHECKeqList="',paste(RESCHECKeqList,collapse=', '),'"'),'')
)
}
}
if ( grepl('(=|<|>|>=|<=|!=|&|\\|)',outFUN))
stop(callerName,'syntax error in FUNCTION definition "',outFUN,'" in OptimizeFunctions$',idxN,'. No logical nor assignment operators allowed in function definition.')
outFUN=.MODEL_MOD_FUNC_NAMES(outFUN)
outFUN=.appendIndexToVars(outFUN,c(model_vexog,
model_vendog)
,'0')
#explode model funs
tempS=.explodeTSLAG(outFUN)
tempS=.explodeTSLEAD(tempS$output)
tempS=.explodeTSDELTA(tempS$output)
tempS=.explodeTSDELTAP(tempS$output)
tempS=.explodeTSDELTALOG(tempS$output)
tempS=.explodeMTOT(tempS$output)
tempS=.explodeMAVE(tempS$output)
outFUN=tempS$output
#stop if the function requires lagging time series more than model equations
tempOut=.getLowerLagAndHigherLead(outFUN)
if (-tempOut$outL>model_max_lag)
stop(callerName,'"OptimizeFunctions$',idxN,'$FUNCTION" expression "',OptimizeFunctions[[idxN]]$FUNCTION,'" requires to lag time series more than model equations do.')
if (tempOut$outH>model_max_lead)
stop(callerName,'"OptimizeFunctions$',idxN,'$FUNCTION" expression "',OptimizeFunctions[[idxN]]$FUNCTION,'" requires to lead time series more than model equations do.')
#add model lag to function expression
outFUN=.addToIndexInString(outFUN, model_max_lag_1)
#append to list
tryCatch({
OptimizeFunctions[[idxN]]$funExpr=parse(text=outFUN)
},error=function(err) stop(callerName,'syntax error in FUNCTION definition "',OptimizeFunctions[[idxN]]$FUNCTION,'" in "OptimizeFunctions$',idxN,'".')
)
}
} else {
stop(callerName,'"OptimizeFunctions" is null in the simulation TSRANGE.\n')
}
# end check OptimizeFunctions
}#end if OPTIMIZE
hasLeads=FALSE
if (model_max_lead>0 || forceForwardLooking)
{
hasLeads=TRUE
}
if (hasLeads && (! (simType %in% (c('RESCHECK','DYNAMIC'))))) stop(callerName,'in forward looking models "simType" must be "DYNAMIC", or "RESCHECK"')
if (hasLeads && verboseSincePeriod > 0) stop(callerName,'"verboseSincePeriod" must be zero in forward looking models.')
# extended tsrange --------------------------------------
#TSRANGE is the simulation range
#EXTENDED_TSRANGE is TSRANGE extended back by model_max_lag periods
#and is used in simulation
#extend TSRANGE by max lag required by model
newStart=normalizeYP(c(TSRANGE[1],TSRANGE[2]-model_max_lag),frequency)
EXTENDED_TSRANGE=TSRANGE
EXTENDED_TSRANGE[1]=newStart[1]
EXTENDED_TSRANGE[2]=newStart[2]
extSimSteps=NUMPERIOD(EXTENDED_TSRANGE[1:2],EXTENDED_TSRANGE[3:4],frequency)+1
# check coefficients exist -----------------------------------------
#create sublists of requested RESCHECK
RESCHECK_behaviorals=NULL
RESCHECK_identities=NULL
if (!is.null(RESCHECKeqList))
{
RESCHECK_behaviorals=base::intersect(RESCHECKeqList,names(model$behaviorals))
RESCHECK_identities =base::intersect(RESCHECKeqList,names(model$identities))
#empty intersect returns character(0) but we need a NULL
if (length(RESCHECK_behaviorals)==0) RESCHECK_behaviorals=NULL
if (length(RESCHECK_identities)==0) RESCHECK_identities=NULL
}
#check behavioral coefficients
if (length(model$behaviorals)>0)
{ if (is.null(RESCHECKeqList))
{
#user requested a full simulation
for (idx in 1:length(model$behaviorals))
{
#check behavioral has coefficients defined and consistent
if (
(length(model$behaviorals[[idx]]$coefficients) != length(model$behaviorals[[idx]]$eqCoefficientsNames)) ||
any( !is.finite(model$behaviorals[[idx]]$coefficients))
)
{
stop(callerName,'please check coefficients definition in behavioral "',
names(model$behaviorals)[[idx]],'" #',idx,' or rerun ESTIMATE().')
}
}
} else
{
#user requested a selection of endogenous rescheck
if (length(RESCHECK_behaviorals)>0)
for (idx in 1:length(RESCHECK_behaviorals))
{
#check behavioral has coefficients defined and consistent
if (
(length(model$behaviorals[[RESCHECK_behaviorals[idx]]]$coefficients) != length(model$behaviorals[[RESCHECK_behaviorals[idx]]]$eqCoefficientsNames)) ||
any( !is.finite(model$behaviorals[[RESCHECK_behaviorals[idx]]]$coefficients))
)
{
stop(callerName,'please check coefficients definition in behavioral "',
RESCHECK_behaviorals[idx],'" or rerun ESTIMATE().')
}
}
}
}
#user requested a selection of endogenous rescheck
if (!is.null(RESCHECKeqList))
{
model_fullComponentList=c()
if (length(RESCHECK_behaviorals)>0)
for (idx in 1:length(RESCHECK_behaviorals))
{
#add local components to list of variables to be proxied
model_fullComponentList=c(model_fullComponentList,
model$behaviorals[[RESCHECK_behaviorals[idx]]]$eqComponentsNames)
}
if (length(RESCHECK_identities)>0)
for (idx in 1:length(RESCHECK_identities))
{
#add local components to list of variables to be proxied
model_fullComponentList=c(model_fullComponentList,model$identities[[RESCHECK_identities[idx]]]$eqComponentsNames)
}
model_vendog=base::intersect(model$vendog,model_fullComponentList)
model_vexog=base::intersect(model$vexog,model_fullComponentList)
model_names_behavioral=base::intersect(names(model$behaviorals),RESCHECK_behaviorals)
model_names_identity=base::intersect(names(model$identities),RESCHECK_identities)
if (! is.null(verboseVars))
{
verboseVars=base::intersect(verboseVars,model_fullComponentList)
if (length(verboseVars)==0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, "verboseVars" is not coherent and will be set equal to "RESCHECKeqList".\n'))
}
}
}
#forecast does not propagate vendog with IF condition...
#model_vendog_no_if contains all vendog but those with IF>
#model_vendog_exogenized == vendog - model_vendog_no_if
model_vendog_no_if=c()
for (idx in 1:length(model_vendog))
{
if (model_vendog[idx] %in% model_names_identity)
{
if (model$identities[[model_vendog[idx]]]$hasIF==FALSE)
{
#no IF so add...
model_vendog_no_if=c(model_vendog_no_if,model_vendog[idx])
}
}
else
{
#we are in behaviorals so no IF allowed
model_vendog_no_if=c(model_vendog_no_if,model_vendog[idx])
}
}
#get exogenized vendog with IF condition (vendog_forecast UNION vendog_exogenized == vendog)
model_vendog_exogenized=base::setdiff(model_vendog,model_vendog_no_if)
if (length(ConstantAdjustment) >0)
for (idxI in 1:length(ConstantAdjustment))
{
idxCA=names(ConstantAdjustment)[idxI]
tryCatch(
{
projectTS=TSPROJECT(ConstantAdjustment[[idxCA]],TSRANGE=EXTENDED_TSRANGE)
outTSL=TSLOOK(projectTS)
.MODEL_outputText(outputText = !quietly,paste0(callerName,'endogenous variable "',
idxCA,
'" has a constant adjustment from year-period ',
paste0(c(outTSL$STARTY,outTSL$STARTP),collapse='-'),
' to ',
paste0(c(outTSL$ENDY,outTSL$ENDP),collapse='-'),'.\n'))
},error=function(e){
.MODEL_outputText(outputText = !quietly,
paste0(callerName,'warning, constant adjustment "',idxCA,'" does not intersect with simulation TSRANGE.\n'))
}
)
}
if (length(Exogenize)>0)
if (MULTMATRIX && length(base::intersect(names(Exogenize),TARGET))>0)
{
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, the following TARGET have been exogenized, therefore related multiplier will be zero: ',paste(base::intersect(names(Exogenize),TARGET),collapse =', '),'.\n'))
}
# deal with leads ----------------------------------
if (hasLeads) {
#SUPER_EXTENDED_TSRANGE is EXTENDED_TSRANGE extended forward by model_max_lead periods
#and is used in matrices dataset building
SUPER_EXTENDED_TSRANGE=EXTENDED_TSRANGE
SUPER_EXTENDED_TSRANGE[3:4]=normalizeYP(c(EXTENDED_TSRANGE[3],EXTENDED_TSRANGE[4]+model_max_lead),frequency)
superExtSimSteps=NUMPERIOD(SUPER_EXTENDED_TSRANGE[1:2],SUPER_EXTENDED_TSRANGE[3:4],frequency)+1
#in case of leads, simulation is performed only on first TSRANGE period
#but simultaneously for all endogenous variable leaded in the whole TSRANGE)
EXTENDED_TSRANGE[3]=TSRANGE[1]
EXTENDED_TSRANGE[4]=TSRANGE[2]
extSimSteps=NUMPERIOD(EXTENDED_TSRANGE[1:2],EXTENDED_TSRANGE[3:4],frequency)+1
}
# create proxies -----------------------------------
#create local proxies (i.e. model variables stored in matrices)
#for all references (i.e. component names used in eq) in behaviorals/identities
#and stores each var as "name"__ORIGINAL__EXTENDED
#deal also with forceForwardLooking, so we need model_max_lead>0
#all components must be project into simSteps+model_max_lead
if (hasLeads && (model_max_lead>0 || simSteps>1)) {
tryCatch(
{
for (idxI in 1:length(model_fullComponentList))
{
tempName=model_fullComponentList[idxI]
#project ts in ext TSRANGE
tsValues=TSPROJECT(model$modelData[[tempName]],
TSRANGE=SUPER_EXTENDED_TSRANGE,
ARRAY=TRUE,
EXTEND=TRUE)
#build matrices (in case of parallel sims)
tempValues=matrix(tsValues,ncol=replica,nrow=superExtSimSteps)
#create proxy for full original time series (on EXTENDED TSRANGE)
#__ORIGINAL__EXTENDED series wont be modified during sim
localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]]=tempValues[1:extSimSteps,,drop=F]
for (idxSS in 1:(model_max_lead+simSteps-1))
{
localE[[paste0(tempName,'__LEAD__',idxSS)]]=tempValues[idxSS+(1:extSimSteps),,drop=F]
}
}
},error=function(e){
stop(callerName,'model data must contain time series "',tempName,'".')
})
} else
{
#no leads
tryCatch(
{
for ( idxI in 1:length(model_fullComponentList))
{
tempName=model_fullComponentList[idxI]
#project ts in ext TSRANGE
tsValues=TSPROJECT(model$modelData[[tempName]],
TSRANGE=EXTENDED_TSRANGE,
ARRAY=TRUE,
EXTEND=TRUE)
#build matrices (in case of parallel sims)
tempValues=matrix(tsValues,ncol=replica,nrow=extSimSteps)
#create proxy for full original time series (on EXTENDED_TSRANGE)
#__ORIGINAL__EXTENDED series wont be modified during sim
localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]]=tempValues
}
},error=function(e){
stop(callerName,'model data must contain time series "',tempName,'".')
})
}
#we need ADDFACTOR only in simulation TSRANGE
tryCatch(
{
#add factor all set to 0
tsValues=rep(0,extSimSteps)
tempValues=matrix(tsValues,ncol=replica,nrow=extSimSteps)
tempS=paste0(model_vendog,'__ADDFACTOR')
for (idxI in 1:length(tempS))
{
tempName=tempS[idxI]
#create proxy for full original time series (on EXTENDED_TSRANGE)
localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]]=tempValues
#this is needed if tmpName time series is not in CA, INSTRUMENT or StochStructure
localE[[paste0(tempName)]]=tempValues
if (hasLeads && simSteps>1) {
#we need ADDFACTOR only in simulation TSRANGE
for (idxSS in 1:(simSteps-1))
{
#create proxy for original time series (on EXTENDED_TSRANGE)
localE[[paste0(tempName,'__LEAD__',idxSS)]]=tempValues
}
}
}
},error=function(e){
stop(callerName,'cannot initialize the constant adjustment of "',tempName,'".')
})
#we need ADDFACTOR only in simulation TSRANGE
if (hasLeads && simSteps>1) {
tryCatch(
{
#... create proxies for explicit Constant Adjustment
if (length(ConstantAdjustment)>0)
for (idxAF in 1:length(ConstantAdjustment))
{
tempName=paste0(names(ConstantAdjustment)[idxAF],'__ADDFACTOR')
#assign from input list to local environment
#project to ext TSRANGE
#we use SUPER_EXTENDED_TSRANGE because original EXTENDED_TSRANGE has been modified
#original EXTENDED_TSRANGE would have been be sufficient
tsValues=TSPROJECT(ConstantAdjustment[[idxAF]],
TSRANGE=SUPER_EXTENDED_TSRANGE,
ARRAY=TRUE,
EXTEND=TRUE)
#replace NA with 0 (EXTEND in TSPROJECT has just inserted NA)
tsValues[which(is.na(tsValues))]=0
tempValues=matrix(tsValues,ncol=replica,nrow=superExtSimSteps)
#create proxy for full original time series (on SUPER_EXTENDED_TSRANGE)
localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]]=tempValues[1:extSimSteps,,drop=F]
#we need ADDFACTOR only in simulation TSRANGE
for (idxSS in 1:(simSteps-1))
{
#create proxy for original time series (on EXTENDED_TSRANGE)
localE[[paste0(tempName,'__LEAD__',idxSS)]]=tempValues[idxSS+(1:extSimSteps),,drop=F]
}
}
},error=function(e){
stop(callerName,'unknown error in "ConstantAdjustment" projection of time series "',names(ConstantAdjustment)[idxAF],'".')
})
} else
{ #no (lead && simSteps>1)
tryCatch(
{
#... create proxies for explicit Constant Adjustment
if (length(ConstantAdjustment)>0)
for (idxAF in 1:length(ConstantAdjustment))
{
tempName=paste0(names(ConstantAdjustment)[idxAF],'__ADDFACTOR')
#assign from input list to local environment
#project to ext TSRANGE
tsValues=TSPROJECT(ConstantAdjustment[[idxAF]],
TSRANGE=EXTENDED_TSRANGE,
ARRAY=TRUE,
EXTEND=TRUE)
#replace NA with 0 (EXTEND in TSPROJECT has just inserted NA)
tsValues[which(is.na(tsValues))]=0
tempValues=matrix(tsValues,ncol=replica,nrow=extSimSteps)
#create proxy for full original time series (on EXTENDED_TSRANGE)
localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]]=tempValues
}
},error=function(e){
stop(callerName,'unknown error in "ConstantAdjustment" projection of time series "',names(ConstantAdjustment)[idxAF],'".')
})
}
#if multipliers requested then modify INSTRUMENTS columns with SHOCKs...
if (MULTMATRIX)
{
tmpI=0
for (idx in 1:length(INSTRUMENT))
{
idxI=INSTRUMENT[idx]
#we need INSTRUMENT column index in matrix MM
tmpI=tmpI+1
#get instrument
tmpM=localE[[paste0(idxI, '__ORIGINAL__EXTENDED')]]
#we need shocked INSTRUMENT only in simulation TSRANGE
for (idxR in 1:simSteps)
{
#shock related column
#get base value
tmpV=tmpM[model_max_lag+idxR,1]
#choice delta
if (tmpV<1) tmpD=MM_SHOCK
else tmpD=tmpV*MM_SHOCK
#apply shock to related column
#each matrix has simsteps x length(INSTRUMENT) columns count
#as well as replica==simsteps x length(INSTRUMENT)+1
tmpM[model_max_lag+idxR,1+(tmpI-1)*simSteps+idxR]=tmpV+tmpD
#save back
localE[[paste0(idxI, '__ORIGINAL__EXTENDED')]]=tmpM
#deal with lead case
if (hasLeads) break
}
if (hasLeads && simSteps>1)
for (idxR in 1:(simSteps-1))
{
#we need shocked INSTRUMENT only in simulation TSRANGE
#get leaded instrument
tmpM=localE[[paste0(idxI,'__LEAD__',idxR)]]
#shock related column
#get base value
tmpV=tmpM[model_max_lag_1,1]
#choice delta
if (tmpV<1) tmpD=MM_SHOCK
else tmpD=tmpV*MM_SHOCK
#apply shock to related column
#each matrix has simsteps x length(INSTRUMENT) columns count
#as well as replica==simsteps x length(INSTRUMENT)+1
tmpM[model_max_lag_1,1+(tmpI-1)*simSteps+(idxR+1)]=tmpV+tmpD
#save back
localE[[paste0(idxI,'__LEAD__',idxR)]]=tmpM
}
}#end INSTRUMENT
}
# check missings and lengths --------------------------------
#trailingTSRANGE = EXTENDED_TSRANGE - TSRANGE
trailingTSRANGE=EXTENDED_TSRANGE
trailingTSRANGE[3:4]=normalizeYP(c(TSRANGE[1],TSRANGE[2]-1),f=frequency)
trailingSteps=extSimSteps-simSteps
#if leads fix trailingSteps
if (hasLeads) trailingSteps=extSimSteps-1
#missing check in first max_lag obs: NA allowed so in case print a warning
#FOLLOWING CODE IS OK ALSO WITH LEADS:
#we dont need to check missing of leaded vars
#in TSRANGE+(1:model_max_lag) because same missings will issue an error
#in check of related non-leaded var in TSRANGE
if (length(model_fullComponentList)>0)
for (idxI in 1:length(model_fullComponentList))
{
idxName=model_fullComponentList[idxI]
tmpProxy=localE[[paste0(idxName,'__ORIGINAL__EXTENDED')]]
#verify there are no missing values in first max_lag values
localMissingIndexes=which(! is.finite(tmpProxy[(1:model_max_lag),]))
#index in GETDATE accounts for replicas
if (length(localMissingIndexes)>0 )
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, ',
ifelse(idxName %in% model_vendog,'endogenous','exogenous'),' variable "',idxName,'" is not fully defined in extended TSRANGE. There are undefined values in year-period ',
paste0(date2yp(as.Date(
GETDATE(TSPROJECT(model$modelData[[idxName]],TSRANGE=trailingTSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% trailingSteps+1)
),f=frequency),collapse = '-'),'.\n'))
}
if (length(ConstantAdjustment)>0)
for (idxI in 1:length(ConstantAdjustment))
{
idxCA=names(ConstantAdjustment)[idxI]
tmpProxy=localE[[paste0(idxCA,'__ADDFACTOR__ORIGINAL__EXTENDED')]]
#verify there are no missing values in first max_lag values
localMissingIndexes=which(! is.finite(tmpProxy[(1:model_max_lag),]))
if (length(localMissingIndexes)>0 )
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, constant adjustment of endogenous variable "',idxCA,'" is not fully defined in extended TSRANGE. There are undefined values in year-period ',
paste0(date2yp(as.Date(
GETDATE(TSPROJECT(ConstantAdjustment[[idxCA]],TSRANGE=trailingTSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% trailingSteps+1)
),f=frequency),collapse = '-'),'.\n'))
}
#check missing and length in vexog time series in TSRANGE: if NA then error
if (length(model_vexog)>0)
for (idxI in 1:length(model_vexog))
{
idxName = (model_vexog)[idxI]
tmpProxy=localE[[paste0(idxName,'__ORIGINAL__EXTENDED')]]
#verify there are no missing values
#we cut first max_lag values that could be unused
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
#index in GETDATE accounts for replicas
if (length(localMissingIndexes)>0 )
{
if (hasLeads)
{
outDate=TSRANGE[1:2]
} else {
outDate=date2yp(as.Date(
GETDATE(TSPROJECT(model$modelData[[idxName]],TSRANGE=TSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% simSteps+1)
),f=frequency)
}
stop(callerName,'exogenous variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(outDate,collapse = '-'),'\n')
}
}
#deal also with forceForwardLooking
#vexog can be leaded too so we need to check up to model_max_lead
if (hasLeads && (simSteps>1 || model_max_lead>0))
{
#vexog in TSRANGE must be defined, after TSRANGE we issue a warning
if (length(model_vexog)>0)
for (idxSS in 1:(model_max_lead+simSteps-1)) for (idxI in 1:length(model_vexog))
{
idxName = (model_vexog)[idxI]
tmpProxy=localE[[paste0(idxName,'__LEAD__',idxSS)]]
#verify there are no missing values
#we cut first max_lag values that could be unused
#in replicas we could have not only just 1 but also up to 1:(replicas+1)
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
#index in GETDATE accounts for replicas
if (length(localMissingIndexes)>0 )
{
realYP=normalizeYP(c(TSRANGE[1],TSRANGE[2]+idxSS),frequency)
if (idxSS <= simSteps-1)
{
#we are in TSRANGE so missing -> stop
stop(callerName,'exogenous variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(realYP,collapse = '-'),'\n')
} else {
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, exogenous variable "',idxName,'" is not fully defined in extended TSRANGE. There are undefined values in year-period ',
paste0(realYP,collapse = '-'),'\n'))
}
}
}
}
#check missing and length in endo exogenized time series (i.e. with IF) inside TSRANGE: if NA then error
#lead case is included in model_vendog check (later in code)
if (length(model_vendog_exogenized)>0 && hasLeads==FALSE)
for (idxI in 1:length(model_vendog_exogenized))
{
idxName=model_vendog_exogenized[idxI]
tmpProxy=localE[[paste0(idxName,'__ORIGINAL__EXTENDED')]]
#verify there are no missing values
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
if (length(localMissingIndexes)>0 )
stop(callerName,'exogenized variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(date2yp(as.Date(
GETDATE(TSPROJECT(model$modelData[[idxName]],TSRANGE=TSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% simSteps+1)
),f=frequency),collapse = '-'),'.\n')
}
#check missing and length in vendog time series inside TSRANGE: if NA then ...depends on simType
for ( idxI in 1:length(model_vendog))
{
idxName=model_vendog[idxI]
tmpProxy=localE[[paste0(idxName, '__ORIGINAL__EXTENDED')]]
#verify there are no missing values
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
#in DYNAMIC and FORECAST sim we can allow missings in trailing obs, but not in leads model
if (length(localMissingIndexes)>0 )
{
if ((simType=='DYNAMIC' || simType == 'FORECAST') && hasLeads==FALSE)
{
if (simType != 'FORECAST') .MODEL_outputText(outputText = !quietly,
paste0('\n',callerName,'warning, endogenous variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(date2yp(as.Date(
GETDATE(TSPROJECT(model$modelData[[idxName]],TSRANGE=TSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% simSteps+1)
),f=frequency),collapse = '-'),'.\n'))
if (simType=='DYNAMIC')
{
.MODEL_outputText(outputText = !quietly,paste0('Simulation will continue replicating last observation in time series "', idxName,'" over the full TSRANGE. Use the "FORECAST" option in "simType" argument to avoid this message.\n'))
}
#should never happen
if (all(! is.finite(tmpProxy)))
stop(callerName,'all endogenous time series "', idxName,'" values are undefined in the extended TSRANGE. Cannot initialize the simulation.')
#here we propagate last known finite observation if any trailing missing
localMissingIndexes=which(! is.finite(tmpProxy))
numRows=dim(tmpProxy)[1]
#replicate last known finite observation
if (length(localMissingIndexes)>0 && numRows>1)
for (idxR in 2:numRows)
if (any(! is.finite(tmpProxy[idxR,]))) tmpProxy[idxR,]=tmpProxy[idxR-1,]
#update original and current time series
localE[[paste0(idxName,'__ORIGINAL__EXTENDED')]]=tmpProxy
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
#check all missings are gone (may be we have NA inside TSRANGE but latest obs are ok)
if (length(localMissingIndexes)>0 )
stop(paste0('\n',callerName,'endogenous variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(date2yp(as.Date(
GETDATE(TSPROJECT(model$modelData[[idxName]],TSRANGE=TSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% simSteps+1)
),f=frequency),collapse = '-'),'.\n'))
}
else
{
#STATIC or RESCHECK or leads
if (hasLeads)
{
#in leaded model TSRANGE[1:2] is the single and last simulation period
outDate=TSRANGE[1:2]
} else {
outDate=date2yp(as.Date(
GETDATE(TSPROJECT(model$modelData[[idxName]],TSRANGE=TSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% simSteps+1)
),f=frequency)
}
#missings are not allowed on STATIC or RESCHECK or leads
stop(callerName,'endogenous variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(outDate,collapse = '-'),'.')
}
}
}
#deal also with forceForwardLooking
#check leaded vendog
if (hasLeads && (simSteps>1 || model_max_lead>0))
{
#if we have leads, vendog in TSRANGE must be defined.
#we do not allow missings neither in DYNAMIC simulation
#(i.e. no replication of last known finite value allowed:
#probably we need finite values also after TSRANGE
#so has no meaning to allow missing values inside TSRANGE).
#FORECAST simulation is not feasible with leads
if (length(model_vendog)>0)
for (idxSS in 1:(model_max_lead+simSteps-1)) for (idxI in 1:length(model_vendog))
{
idxName=model_vendog[idxI]
tmpProxy=localE[[paste0(idxName,'__LEAD__',idxSS)]]
#verify there are no missing values
#in replicas we could have not only just 1 but up to 1:(replicas+1)
#note: all missings/NaNs are converted in zeros before in code
#when dealing with add-factor projection in TSRANGE
#so probably this check is redundant
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
if (length(localMissingIndexes)>0 )
{
#missings are not allowed
realYP=normalizeYP(c(TSRANGE[1],TSRANGE[2]+idxSS),frequency)
if (idxSS <= simSteps-1)
{
#we are in TSRANGE so missing -> stop
stop(callerName,'endogenous variable "',idxName,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(realYP,collapse = '-'),'\n')
} else {
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, endogenous variable "',idxName,'" is not fully defined in extended TSRANGE. There are undefined values in year-period ',
paste0(realYP,collapse = '-'),'\n'))
}
}
}
}
#check missing and length in CA time series inside TSRANGE: if NA then stop
if (length(ConstantAdjustment)>0)
for ( idxI in 1:length(ConstantAdjustment))
{
idxCA=names(ConstantAdjustment)[idxI]
tmpProxy=localE[[paste0(idxCA,'__ADDFACTOR__ORIGINAL__EXTENDED')]]
#verify there are no missing values
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
if (length(localMissingIndexes)>0 )
{
if (hasLeads)
{
#this is only the base case; leads are analyzed later
outDate=TSRANGE[1:2]
} else {
outDate=date2yp(as.Date(
GETDATE(TSPROJECT(ConstantAdjustment[[idxCA]],TSRANGE=TSRANGE,EXTEND=TRUE),
(localMissingIndexes[length(localMissingIndexes)]-1) %% simSteps+1)
),f=frequency)
}
stop(callerName,'constant adjustment of endogenous variable "',idxCA,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(outDate,collapse = '-'),'.\n')
}
}
if (hasLeads && simSteps>1)
{
#check missing and length in CA time series inside TSRANGE: if NA then stop
if (length(ConstantAdjustment)>0)
for (idxSS in 1:(model_max_lead+simSteps-1)) for (idxI in 1:length(ConstantAdjustment))
{
idxCA=names(ConstantAdjustment)[idxI]
tmpProxy=localE[[paste0(idxCA,'__ADDFACTOR__LEAD__',idxSS)]]
#verify there are no missing values
#note: all missings/NaNs are converted in zeros before in code
#when dealing with add-factor projection in TSRANGE
#so probably this check is redundant
localMissingIndexes=which(! is.finite(tmpProxy[-(1:model_max_lag),]))
if (length(localMissingIndexes)>0 )
{
realYP=normalizeYP(c(TSRANGE[1],TSRANGE[2]+idxSS),frequency)
if (idxSS <= simSteps-1)
{
#we are in TSRANGE so missing -> stop
stop(callerName,'constant adjustment of endogenous variable "',idxCA,'" is not fully defined in TSRANGE. There are undefined values in year-period ',
paste0(realYP,collapse = '-'),'\n')
} else {
.MODEL_outputText(outputText = !quietly,paste0(callerName,'warning, constant adjustment of endogenous variable "',idxCA,'" is not fully defined in extended TSRANGE. There are undefined values in year-period ',
paste0(realYP,collapse = '-'),'\n'))
}
}
}
}
#backupped and later saved in __SIM_PARAMETERS__
Exogenize_original=Exogenize
#print messages....
if (length(Exogenize_original) > 0)
for (idxI in 1:length(Exogenize_original))
{
idxEL=names(Exogenize_original)[idxI]
.MODEL_outputText(outputText = !quietly,paste0(callerName,'endogenous variable "',
idxEL,
'" has been exogenized from year-period ',
paste0(Exogenize[[idxEL]][1:2],collapse='-'),
' to ',
paste0(Exogenize[[idxEL]][3:4],collapse='-'),'.\n'))
#convert to indexes
Exogenize[[idxEL]] = c(
(NUMPERIOD(TSRANGE[1:2],Exogenize[[idxEL]][1:2],frequency)+1):
(NUMPERIOD(TSRANGE[1:2],Exogenize[[idxEL]][3:4],frequency)+1)
)
#deal with exogenization in leads
#e.g. exogenize y=2,3 then
#y_lead_1=1, y_lead_2=1
if (hasLeads && simSteps>1 )
{
preLeadValules=Exogenize[[idxEL]] #these are integers
Exogenize[[idxEL]]=NULL
for (idxEP in preLeadValules)
{
if (idxEP==1)
{
Exogenize[[idxEL]]=1
} else {
Exogenize[[paste0(idxEL,'__LEAD__',idxEP-1)]]=1
}
}
}
}
#backupped and later saved in simulate_parameters
StochStructure_original=StochStructure
OptimizeRestrictions_original=OptimizeRestrictions
#print messages....
if (STOCHSIMULATE && length(StochStructure)>0)
for (idxI in 1:length(StochStructure))
{
idxSS=names(StochStructure)[idxI]
typePertS=''
if (StochStructure[[idxSS]]$TYPE=='UNIF') typePertS='uniformly'
if (StochStructure[[idxSS]]$TYPE=='NORM') typePertS='normally'
if (StochStructure[[idxSS]]$TYPE=='MATRIX') typePertS='manually'
.MODEL_outputText(outputText = !quietly,paste0(callerName,'',ifelse(idxSS %in% model_vendog,'endogenous variable "','exogenous variable "'),
idxSS,
'" has been ',typePertS,' perturbed from year-period ',
paste0(StochStructure[[idxSS]]$TSRANGE[1:2],collapse='-'),
' to ',
paste0(StochStructure[[idxSS]]$TSRANGE[3:4],collapse='-'),'.\n'))
#convert to indexes
StochStructure[[idxSS]]$TSRANGE = c(
(NUMPERIOD(EXTENDED_TSRANGE[1:2],StochStructure[[idxSS]]$TSRANGE[1:2],frequency)+1):
(NUMPERIOD(EXTENDED_TSRANGE[1:2],StochStructure[[idxSS]]$TSRANGE[3:4],frequency)+1)
)
if (StochStructure[[idxSS]]$TYPE == 'MATRIX')
{
if( (nrow(StochStructure[[idxSS]]$PARS) != length(StochStructure[[idxSS]]$TSRANGE)) ||
(ncol(StochStructure[[idxSS]]$PARS) != (replica-1)) )
stop(callerName,paste0('"StochStructure$',idxSS,'PARS" must be a ',length(StochStructure[[idxSS]]$TSRANGE),' x ',replica-1,' matrix (i.e. "periods in TSRANGE" x "StochReplica").'))
}
}
if (OPTIMIZE)
{
if(length(OptimizeBounds)>0)
{
for (idxI in 1:length(OptimizeBounds))
{
idxSS=names(OptimizeBounds)[idxI]
.MODEL_outputText(outputText = !quietly,paste0(callerName,'optimization boundaries for the ',ifelse(idxSS %in% model_vendog,'add-factor of endogenous variable "','exogenous variable "'),
idxSS,
'" are (',paste0(OptimizeBounds[[idxSS]]$BOUNDS[1:2],collapse=','),') from year-period ',
paste0(OptimizeBounds[[idxSS]]$TSRANGE[1:2],collapse='-'),
' to ',
paste0(OptimizeBounds[[idxSS]]$TSRANGE[3:4],collapse='-'),'.\n'))
#convert to indexes
OptimizeBounds[[idxSS]]$TSRANGE = c(
(NUMPERIOD(EXTENDED_TSRANGE[1:2],OptimizeBounds[[idxSS]]$TSRANGE[1:2],frequency)+1):
(NUMPERIOD(EXTENDED_TSRANGE[1:2],OptimizeBounds[[idxSS]]$TSRANGE[3:4],frequency)+1)
)
}
}
if(length(OptimizeRestrictions)>0)
{
for (idxI in 1:length(OptimizeRestrictions))
{
idxSS=names(OptimizeRestrictions)[idxI]
.MODEL_outputText(outputText = !quietly,paste0(callerName,'optimization restriction "',
idxSS,'" is active from year-period ',
paste0(OptimizeRestrictions[[idxSS]]$TSRANGE[1:2],collapse='-'),
' to ',
paste0(OptimizeRestrictions[[idxSS]]$TSRANGE[3:4],collapse='-'),'.\n'))
#convert to indexes
OptimizeRestrictions[[idxSS]]$TSRANGE = c(
(NUMPERIOD(EXTENDED_TSRANGE[1:2],OptimizeRestrictions[[idxSS]]$TSRANGE[1:2],frequency)+1):
(NUMPERIOD(EXTENDED_TSRANGE[1:2],OptimizeRestrictions[[idxSS]]$TSRANGE[3:4],frequency)+1)
)
}
}
if(length(OptimizeFunctions)>0)
{
for (idxI in 1:length(OptimizeFunctions))
{
idxSS=names(OptimizeFunctions)[idxI]
.MODEL_outputText(outputText = !quietly,paste0(callerName,'objective function "',
idxSS,'" is active from year-period ',
paste0(OptimizeFunctions[[idxSS]]$TSRANGE[1:2],collapse='-'),
' to ',
paste0(OptimizeFunctions[[idxSS]]$TSRANGE[3:4],collapse='-'),'.\n'))
#convert to indexes
OptimizeFunctions[[idxSS]]$TSRANGE = c(
(NUMPERIOD(EXTENDED_TSRANGE[1:2],OptimizeFunctions[[idxSS]]$TSRANGE[1:2],frequency)+1):
(NUMPERIOD(EXTENDED_TSRANGE[1:2],OptimizeFunctions[[idxSS]]$TSRANGE[3:4],frequency)+1)
)
}
}
}
# add stoch noise ----------------------------------------------------------------------------------------
#add noise to selected vars
if (STOCHSIMULATE)
{
#store var for perturbed instruments
INSTRUMENT_MM=list()
if (length(StochStructure)>0)
{
for (idxI in 1:length(StochStructure))
{
idxN=names(StochStructure)[idxI]
if ( (! is.null(RESCHECKeqList)) && length(base::intersect(idxN,model_fullComponentList))==0)
{
#with RESCHECK user can select eq to be simulated
#so idxN could be not in vendog nor in vexog
.MODEL_outputText(outputText =!quietly,paste0(callerName,'warning, "',idxN,'" appears in "StochStructure" but it is not required in order to perform the simulations requested in "RESCHECKeqList". It will be skipped.\n'))
next
}
#create uniform perturbation
if (StochStructure[[idxN]]$TYPE=='UNIF')
noise=matrix(
stats::runif(
length(StochStructure[[idxN]]$TSRANGE)*(replica-1),
min=StochStructure[[idxN]]$PARS[1],
max=StochStructure[[idxN]]$PARS[2])
,nrow=length(StochStructure[[idxN]]$TSRANGE)
)
#create normal perturbation
if (StochStructure[[idxN]]$TYPE=='NORM')
noise=matrix(
stats::rnorm(
length(StochStructure[[idxN]]$TSRANGE)*(replica-1),
mean=StochStructure[[idxN]]$PARS[1],
sd=StochStructure[[idxN]]$PARS[2])
,nrow=length(StochStructure[[idxN]]$TSRANGE)
)
#pass perturbation matrix to model
if (StochStructure[[idxN]]$TYPE=='MATRIX')
{
noise=StochStructure[[idxN]]$PARS
}
if (hasLeads && simSteps>1)
{
for (idxSS in 1:(simSteps))
{
if (idxN %in% model_vendog)
{
if (idxSS==1)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ADDFACTOR__ORIGINAL__EXTENDED')]]
} else {
#get un-noised leaded time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ADDFACTOR__LEAD__',(idxSS-1))]]
}
} else if (idxN %in% model_vexog)
{
if (idxSS==1)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]
} else {
#get un-noised leaded time series
tmpNoised_ORIG=localE[[paste0(idxN,'__LEAD__',(idxSS-1))]]
}
} else
{
stop(callerName,'unknown error while perturbing time series "',idxN,'".')
}
if ((extSimSteps+idxSS-1) %in% StochStructure[[idxN]]$TSRANGE)
{
noise_lead=noise[(extSimSteps+idxSS-1)-StochStructure[[idxN]]$TSRANGE[1]+1,,drop=F]
#add noise to matrix data (replace if MATRIX and EXOG)
if ((StochStructure[[idxN]]$TYPE=='MATRIX') && (idxN %in% model_vexog))
{
tmpNoised_ORIG[extSimSteps,2:replica]=noise_lead
} else
{
tmpNoised_ORIG[extSimSteps,2:replica]=tmpNoised_ORIG[extSimSteps,2:replica]+noise_lead
}
if (idxN %in% model_vendog)
{
if (idxSS==1)
{
#save noised ts
localE[[paste0(idxN,'__ADDFACTOR','__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else {
#save noised ts
localE[[paste0(idxN,'__ADDFACTOR','__LEAD__',(idxSS-1))]]=tmpNoised_ORIG
}
} else if (idxN %in% model_vexog)
{
if (idxSS==1)
{
#save noised ts
localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else {
#save noised ts
localE[[paste0(idxN,'__LEAD__',(idxSS-1))]]=tmpNoised_ORIG
}
} else stop(callerName,'unknown error while storing perturbed time series "',idxN,'".')
}#simStep is in TSRANGE
if (idxSS==1)
{
#store perturbed ts for output
INSTRUMENT_MM[[idxN]]=tmpNoised_ORIG[extSimSteps,,drop=F]
} else {
#store perturbed ts for output
INSTRUMENT_MM[[paste0(idxN,'__LEAD__',(idxSS-1))]]=tmpNoised_ORIG[extSimSteps,,drop=F]
}
}#cycle in simSteps
} else {#hasleads=FALSE
if (idxN %in% model_vendog)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ADDFACTOR__ORIGINAL__EXTENDED')]]
} else if(idxN %in% model_vexog)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]
} else stop(callerName,'unknown error while perturbing time series "',idxN,'".')
#add noise to matrix data (replace if MATRIX and EXOG)
if ((StochStructure[[idxN]]$TYPE=='MATRIX') && (idxN %in% model_vexog))
{
tmpNoised_ORIG[StochStructure[[idxN]]$TSRANGE,2:replica]=noise
} else
{
tmpNoised_ORIG[StochStructure[[idxN]]$TSRANGE,2:replica]=tmpNoised_ORIG[StochStructure[[idxN]]$TSRANGE,2:replica]+noise
}
if (idxN %in% model_vendog)
{
#save noised ts
localE[[paste0(idxN,'__ADDFACTOR','__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else if(idxN %in% model_vexog)
{
#save noised ts
localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else stop(callerName,'unknown error while storing perturbed time series "',idxN,'".')
#store perturbed ts for output
INSTRUMENT_MM[[idxN]]=tmpNoised_ORIG[-(1:model_max_lag),,drop=F]
} #else has leads
}
}
}
# populate optimization search domain --------------------------------------------------------------
#populate search domain
if (OPTIMIZE)
{
#store var for perturbed instruments
INSTRUMENT_MM=list()
#columns to be kept after optimization restrictions
optColsToBeKept=rep(TRUE,replica-1)
#optimize function results
optFunResults=rep(0,replica-1)
#optimize fun time series
optFunTSMM=c()
optFunTS=NULL
if (length(OptimizeBounds)>0)
{
for (idxI in 1:length(OptimizeBounds))
{
idxN=names(OptimizeBounds)[idxI]
if ( ! is.null(RESCHECKeqList) && length(base::intersect(idxN,model_fullComponentList))==0)
{
#with RESCHECK user can select eq to be simulated
#so idxN could be not in vendog nor in vexog
.MODEL_outputText(outputText =!quietly,paste0(callerName,'warning, "',idxN,'" appears in "OptimizeBounds" but it is not required in order to perform the simulations requested in "RESCHECKeqList". It will be skipped.\n'))
next
}
#create unif noise in range
noise=matrix(
stats::runif(
length(OptimizeBounds[[idxN]]$TSRANGE)*(replica-1),
min=OptimizeBounds[[idxN]]$BOUNDS[1],
max=OptimizeBounds[[idxN]]$BOUNDS[2])
,nrow=length(OptimizeBounds[[idxN]]$TSRANGE)
)
if (hasLeads && simSteps>1)
{
for (idxSS in 1:(simSteps))
{
if (idxN %in% model_vendog)
{
if (idxSS==1)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ADDFACTOR__ORIGINAL__EXTENDED')]]
} else {
#get un-noised leaded time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ADDFACTOR__LEAD__',(idxSS-1))]]
}
} else if (idxN %in% model_vexog)
{
if (idxSS==1)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]
} else {
#get un-noised leaded time series
tmpNoised_ORIG=localE[[paste0(idxN,'__LEAD__',(idxSS-1))]]
}
} else stop(callerName,'unknown error while populating time series "',idxN,'".')
if ((extSimSteps+idxSS-1) %in% OptimizeBounds[[idxN]]$TSRANGE)
{
noise_lead=noise[(extSimSteps+idxSS-1)-OptimizeBounds[[idxN]]$TSRANGE[1]+1,,drop=F]
#replace matrix data
tmpNoised_ORIG[extSimSteps,2:replica]=noise_lead
if (idxN %in% model_vendog)
{
if (idxSS==1)
{
#save populated ts
localE[[paste0(idxN,'__ADDFACTOR__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else {
#save noised ts
localE[[paste0(idxN,'__ADDFACTOR','__LEAD__',(idxSS-1))]]=tmpNoised_ORIG
}
} else if (idxN %in% model_vexog)
{
if (idxSS==1)
{
#save populated ts
localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else {
#save noised ts
localE[[paste0(idxN,'__LEAD__',(idxSS-1))]]=tmpNoised_ORIG
}
} else stop(callerName,'unknown error while storing populated time series "',idxN,'".')
}#simStep is in TSRANGE
if (idxSS==1)
{
#store perturbed ts for output
INSTRUMENT_MM[[idxN]]=tmpNoised_ORIG[extSimSteps,,drop=F]
} else {
#store perturbed ts for output
INSTRUMENT_MM[[paste0(idxN,'__LEAD__',(idxSS-1))]]=tmpNoised_ORIG[extSimSteps,,drop=F]
}
} #end cycle idxSS simSteps
} else { #hasleads==FALSE
if (idxN %in% model_vendog)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ADDFACTOR__ORIGINAL__EXTENDED')]]
} else if (idxN %in% model_vexog)
{
#get un-noised time series
tmpNoised_ORIG=localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]
} else stop(callerName,'unknown error while populating time series "',idxN,'".')
#replace matrix data
tmpNoised_ORIG[OptimizeBounds[[idxN]]$TSRANGE,2:replica]=noise
if (idxN %in% model_vendog)
{
#save populated ts
localE[[paste0(idxN,'__ADDFACTOR__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else if (idxN %in% model_vexog)
{
#save populated ts
localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]=tmpNoised_ORIG
} else stop(callerName,'unknown error while storing populated time series "',idxN,'".')
#store perturbed ts for output
INSTRUMENT_MM[[idxN]]=tmpNoised_ORIG[-(1:model_max_lag),,drop=F]
}
}
}
}
# populate behaviorals coefficient -------------------------------------------------------
#temp list with sim results
simulation=list()
.MODEL_outputText(outputText=!quietly,"\n")
if (length(model_names_behavioral)>0)
for (idxI in 1:length(model_names_behavioral))
{
currentVendog=model_names_behavioral[idxI]
#cycle in endogenous
#get eq components names and assign into them the behavioral coefficient values
currentBehavioral=model$behaviorals[[currentVendog]]
#get names of coefficients for current behavioral endogenous
localCoefficientNames=currentBehavioral$eqCoefficientsNames
#get values of coefficients for current behavioral endogenous
localCoefficientValues=c(currentBehavioral$coefficients)
#check there is a coefficient value for every coefficient name
if (length(localCoefficientNames) != length(localCoefficientValues))
stop(callerName,'coefficients count error in behavioral "',currentVendog,'".')
#assign values to coefficients
for (idxA in 1:length(localCoefficientValues))
{
localE[[paste0(currentVendog,'__COEFF__',localCoefficientNames[idxA])]]=localCoefficientValues[idxA]
}
#assign values to error coefficients
if ( ! is.null(currentBehavioral$errorType) && currentBehavioral$errorType=='AUTO')
{
for (idxEC in 1:currentBehavioral$errorDim)
{
#check if rhos have to be zeroed
if (ZeroErrorAC)
{
localE[[paste0(currentVendog,'__RHO__',idxEC)]]=0
}
else
{
localE[[paste0(currentVendog,'__RHO__',idxEC)]]=currentBehavioral$errorCoefficients[idxEC]
}
}
}# end deal with AUTO
}#for in model_names_behaviorals
# build sim expressions -------------------------------------------------------
if (hasLeads && simSteps>1)
{
#cycle behaviorals
if (simSteps>1 && length(model_names_behavioral)>0) for (idx in 1:length(model_names_behavioral))
{
currentVendog=model_names_behavioral[idx]
#lead vendog sim eq up to simSteps, and convert to __LEAD__ when i>model_max_lax+1,
#given vendog[i,] in sim eq
model$behaviorals[[currentVendog]]$leadsEqSimExpText=.leadEqSim(currentVendog,
model$behaviorals[[currentVendog]]$eqSimExpText,
model_max_lag_1,
simSteps)
#parse text eq
model$behaviorals[[currentVendog]]$leadsEqSimExp=lapply(model$behaviorals[[currentVendog]]$leadsEqSimExpText,
function(x) parse(text=x))
}
if (simSteps>1 && length(model_names_identity)>0) for (idx in 1:length(model_names_identity))
{
currentVendog=model_names_identity[idx]
#lead vendog sim eq up to simSteps, and convert to __LEAD__ when i>model_max_lax+1,
#given vendog[i,] in sim eq
model$identities[[currentVendog]]$leadsEqSimExpText=.leadEqSim(currentVendog,
model$identities[[currentVendog]]$eqSimExpText, #ok with IF> in identity
model_max_lag_1,
simSteps)
#parse text eq
model$identities[[currentVendog]]$leadsEqSimExp=lapply(model$identities[[currentVendog]]$leadsEqSimExpText,
function(x) parse(text=x))
}
}
# build lead incidence and order lists ---------------------------------------
#build incidence matrix with leads (RESCHECK excluded)
if (hasLeads && simType=='DYNAMIC')
{
.MODEL_outputText(outputText=!quietly,'Optimizing forward looking...\n')
#create empty incidence matrix
incidence_matrix_size=length(model_vendog)*simSteps
incidence_matrix=matrix(0,nrow=incidence_matrix_size, ncol=incidence_matrix_size)
if (simSteps==1)
{
colnames(incidence_matrix)=model_vendog
rownames(incidence_matrix)=model_vendog
} else {
tmpNames=model_vendog
tmpS=paste0(model_vendog,'__LEAD__')
for (idxSS in 1:(simSteps-1))
{
tmpNames=c(tmpNames,paste0(tmpS,idxSS))
}
colnames(incidence_matrix)=tmpNames
rownames(incidence_matrix)=tmpNames
}
#build ordered lists
if (length(model_names_behavioral)>0)
for (idxI in 1:length(model_names_behavioral))
{
currentVendog=model_names_behavioral[idxI]
#get non vexogs components
baseVendogComponents=c(model$behaviorals[[currentVendog]]$eqComponentsNamesBehaviorals,
model$behaviorals[[currentVendog]]$eqComponentsNamesIdentities)
vendogComponents=c()
if (simSteps>1)
{
tmpS=paste0(baseVendogComponents,'__LEAD__')
for (idxSS in 1:(simSteps-1))
vendogComponents=c(vendogComponents,paste0(tmpS,idxSS))
}
#extend list with leaded components
vendogComponents=c(baseVendogComponents,vendogComponents)
#extract current and leaded components that produce incidence
#current...
incidenceVendogs=.getIncidenceVendogs(currentVendog,
model$behaviorals[[currentVendog]]$eqSimExpLeadedText,
vendogComponents,
baseIndex=model_max_lag_1)
if (length(incidenceVendogs)>0)
for (idxIV in 1:length(incidenceVendogs))
incidence_matrix[currentVendog,
incidenceVendogs[idxIV]]=1
#leaded...
if (simSteps>1)
{
tmpNames=names(model$behaviorals[[currentVendog]]$leadsEqSimExp)
for (idxII in 1:length(model$behaviorals[[currentVendog]]$leadsEqSimExp))
{
idxSE=tmpNames[idxII]
incidenceVendogs=.getIncidenceVendogs(idxSE,
model$behaviorals[[currentVendog]]$leadsEqSimExpText[[idxSE]],
vendogComponents,
baseIndex=model_max_lag_1)
if (length(incidenceVendogs)>0)
for (idxIV in 1:length(incidenceVendogs))
incidence_matrix[idxSE,
incidenceVendogs[idxIV]]=1
}
}
}
if (length(model_names_identity)>0)
for (idxI in 1:length(model_names_identity))
{
currentVendog=model_names_identity[idxI]
#get non vegoxs components
baseVendogComponents=c(model$identities[[currentVendog]]$eqComponentsNamesBehaviorals,
model$identities[[currentVendog]]$eqComponentsNamesIdentities)
vendogComponents=c()
if (simSteps>1)
{
tmpS=paste0(baseVendogComponents,'__LEAD__')
for (idxSS in 1:(simSteps-1))
vendogComponents=c(vendogComponents,paste0(tmpS,idxSS))
}
#extend list with leaded component
vendogComponents=c(baseVendogComponents,vendogComponents)
#extract current and leaded components that produce incidence
#current...
incidenceVendogs=.getIncidenceVendogs(currentVendog,
model$identities[[currentVendog]]$eqSimExpLeadedText,#ok with IF> in identity
vendogComponents,
baseIndex=model_max_lag_1)
if (length(incidenceVendogs)>0)
for (idxIV in 1:length(incidenceVendogs))
incidence_matrix[currentVendog,
incidenceVendogs[idxIV]]=1
#leaded...
if (simSteps>1)
{
tmpNames=names(model$identities[[currentVendog]]$leadsEqSimExp)
for (idxII in 1:length(model$identities[[currentVendog]]$leadsEqSimExp))
{
idxSE=tmpNames[idxII]
eqSimText=model$identities[[currentVendog]]$leadsEqSimExpText[[idxSE]]
incidenceVendogs=.getIncidenceVendogs(idxSE,
eqSimText,
vendogComponents,
baseIndex=model_max_lag_1)
if (length(incidenceVendogs)>0)
for (idxIV in 1:length(incidenceVendogs))
incidence_matrix[idxSE,
incidenceVendogs[idxIV]]=1
}
}
}
#get vblocks from incidence matrix using Tarjan
modelBlocks=.buildBlocks(incidence_matrix)
model_vblocks=modelBlocks$vblocks
length_model_vblocks=length(model_vblocks)
model_vpre=modelBlocks$vpre
length_model_vpre=length(model_vpre)
}#end has leads
# build sim expressions lists -------------------------------------------------------
if (length_model_vblocks>0)
for (idxB in 1:length_model_vblocks)
{
model_vsim[[idxB]]=model_vblocks[[idxB]]$vsim
model_vfeed[[idxB]]=model_vblocks[[idxB]]$vfeed
length_model_vsim=c(length_model_vsim,length(model_vsim[[idxB]]))
length_model_vfeed=c(length_model_vfeed,length(model_vfeed[[idxB]]))
model_vpost[[idxB]]=model_vblocks[[idxB]]$vpost
length_model_vpost=c(length_model_vpost,length(model_vblocks[[idxB]]$vpost))
}
if (! simType =='RESCHECK')
{#full simulation required
#if leads then search for convergence in first period only
if (hasLeads && simSteps>1)
{
actualSimSteps=1
} else {
actualSimSteps=simSteps
}
#array of expressions used in convergence algos
vpre_expressions=vector('list',actualSimSteps)
vsim_expressions=vector('list',actualSimSteps)
vpost_expressions=vector('list',actualSimSteps)
#e.g. vsim_expression[[2]][[3]] is vendog list in simultaneous vblock 3 in simulation period 2
for (idxS in 1:actualSimSteps)
{
vsim_expressions[[idxS]]=vector('list',length_model_vblocks)
vpost_expressions[[idxS]]=vector('list',length_model_vblocks)
}
#support variables, needed for convergence check on feedback variables
localE$SIM__ALGO=simAlgo
#model vfeed proxy
localE$MODEL__VFEED__LIST=model_vfeed
#model vfeed length proxy
localE$LENGTH__MODEL__VFEED__LIST=length_model_vfeed
#model_max_lag + 1 proxy
localE$MODEL__MAX__LAG__1=model_max_lag_1
#model replica proxy
localE$REPLICA__=replica
#newton methods, we need more info copied into localE
if (simAlgo!='GAUSS-SEIDEL')
{
if (length_model_vblocks>0) {
#vfeed active in jacobian
localE$JACOBIAN__VFEED__ACTIVE__LIST=list()
for (idxB in 1:length_model_vblocks)
localE$JACOBIAN__VFEED__ACTIVE__LIST[[idxB]]=matrix(1,ncol=actualSimSteps,nrow=length_model_vfeed[idxB])
#init jacobian matrix
if (simAlgo=='NEWTON')
{
localE$JACOBIAN__SINGLE__MATRIX__ACTIVE__LIST=list()
} else { #FULLNEWTON
localE$JACOBIAN__FULL__MATRIX__ACTIVE__LIST=list()
}
#assign default shock to jacobian (note double underscore)
localE$JACOBIAN__SHOCK=JACOBIAN_SHOCK
#jacobian scale values
localE$JACOBIAN__SCALE__VALUE__LIST=list()
for (idxB in 1:length_model_vblocks)
localE$JACOBIAN__SCALE__VALUE__LIST[[idxB]]=matrix(1,ncol=replica,nrow=length_model_vfeed[idxB])
#flag of jacobian recalculation
localE$RECALCULATE__JACOBIAN__ARRAY=vector(mode='logical',length=length_model_vblocks)
localE$RECALCULATE__JACOBIAN__ARRAY[]=TRUE
}
}
#LAST__EVAL__EQ is used in debug and error message: it keeps name of last evaluated eq during sim
localE$LAST__EVAL__EQ='unknown'
#init newton stuff...
if (simAlgo!='GAUSS-SEIDEL' && length_model_vblocks>0)
{
#populate matrix of active vfeed in jacobian
#Exogenize or Drop can reduce the vfeed set active in Jacobian
#purge vfeed list from lead suffix
model_vfeed_prefix=c()
for (idxB in 1:length_model_vblocks) model_vfeed_prefix=c(model_vfeed_prefix,model_vfeed[[idxB]])
if (hasLeads && simSteps>1) model_vfeed_prefix=unique(unlist(lapply(strsplit(model_vfeed_prefix,'__LEAD__'), function(x) return(x[1]))))
#check JacobianDrop
idxToBeRemoved=c()
if (length(JacobianDrop)>0)
for (idx in 1:length(JacobianDrop))
if (! JacobianDrop[idx] %in% model_vfeed_prefix )
{
.MODEL_outputText(sep='',outputText=!quietly,callerName,'warning, "',JacobianDrop[idx],'" is not a model feedback variable. It will be removed from the "JacobianDrop" argument\n')
idxToBeRemoved=c(idxToBeRemoved,idx)
}
if (length(idxToBeRemoved)>0) JacobianDrop=JacobianDrop[-idxToBeRemoved]
#disable vfeed idxVF in iteration idxSP if exogenized
for (idxB in 1:length_model_vblocks)
for (idxVF in 1:length_model_vfeed[idxB])
{
vfeedTemp=model_vfeed[[idxB]][idxVF]
#drop from jacobian if exogenized
if (vfeedTemp %in% names(Exogenize))
for (idxSP in 1:actualSimSteps)
{
if ( idxSP %in% Exogenize[[vfeedTemp]])
localE$JACOBIAN__VFEED__ACTIVE__LIST[[idxB]][idxVF,idxSP]=0
}
#drop from jacobian if in JacobianDrop
#purge vfeed from __LEAD__ suffix
if (hasLeads && simSteps>1) vfeedTemp=strsplit(vfeedTemp,'__LEAD__')[[1]][1]
if (vfeedTemp %in% JacobianDrop)
{
localE$JACOBIAN__VFEED__ACTIVE__LIST[[idxB]][idxVF,]=0
}
}
}
#build vpre expression
if (length_model_vpre>0)
{
for (tmpV in (model_vpre))
{
#init tmp var
tmp_expressions=c()
tmpVfull=tmpV
if (hasLeads && simSteps>1 && grepl('__LEAD__',tmpV))
{
tmpV=strsplit(tmpVfull,'__LEAD__')[[1]][1]
#append sim expression
if (tmpV %in% model_names_behavioral)
{
tmp_expressions=model$behaviorals[[tmpV]]$leadsEqSimExp[[tmpVfull]]
} else
{
tmp_expressions=model$identities[[tmpV]]$leadsEqSimExp[[tmpVfull]]
}
} else {
#append sim expression
if (tmpV %in% model_names_behavioral)
{
tmp_expressions=model$behaviorals[[tmpV]]$eqSimExp
} else
{
tmp_expressions=model$identities[[tmpV]]$eqSimExp
}
}
#append check on result
tmp_expressions=c(parse(text=paste0('LAST__EVAL__EQ="',tmpVfull,'";')),
tmp_expressions,
parse(text=paste0('if (any(! is.finite(',tmpVfull,'[',model_max_lag_1,',]))) stop(\'Uncomputable solution or numeric overflow while evaluating \"',tmpV,'\".\');')))
#update vpre expressions, and deal with exogenization
if (! tmpVfull %in% names(Exogenize))
{
for (idxSP in 1:actualSimSteps)
{
vpre_expressions[[idxSP]]=c(vpre_expressions[[idxSP]],tmp_expressions)
}
} else
{
for (idxSP in 1:actualSimSteps)
{
if (! idxSP %in% Exogenize[[tmpVfull]]) vpre_expressions[[idxSP]]=c(vpre_expressions[[idxSP]],tmp_expressions)
}
}
}}#end vpre
if (length_model_vblocks>0)
for (idxB in 1:length_model_vblocks)
{
#get index of first vfeed in vsim
if (length_model_vsim[idxB]>0)
{
vfeedIndexInVsim=which(model_vsim[[idxB]] == model_vfeed[[idxB]][1])
if (length(vfeedIndexInVsim)==0) stop(callerName,'unknown error while splitting vsim vs vfeed in block ',idxB,'.')
#init vfeed__current to initial state (VFEED__NEXT in iteration 1 contains historical values)
tmp_expressions=parse(text='VFEED__CURRENT=VFEED__NEXT')
for (idxSP in 1:actualSimSteps) vsim_expressions[[idxSP]][[idxB]]=c( vsim_expressions[[idxSP]][[idxB]],tmp_expressions)
for (idxE in 1:length_model_vsim[idxB])
{
#init tmp var
tmp_expressions=c()
tmpV=model_vsim[[idxB]][idxE]
tmpVfull=tmpV
if (hasLeads && simSteps>1 && grepl('__LEAD__',tmpV))
{
tmpV=strsplit(tmpVfull,'__LEAD__')[[1]][1]
#append sim expression
if (tmpV %in% model_names_behavioral)
{
tmp_expressions=model$behaviorals[[tmpV]]$leadsEqSimExp[[tmpVfull]]
} else
{
tmp_expressions=model$identities[[tmpV]]$leadsEqSimExp[[tmpVfull]]
}
} else {
#append sim expression
if (tmpV %in% model_names_behavioral)
{
tmp_expressions=model$behaviorals[[tmpV]]$eqSimExp
} else
{
tmp_expressions=model$identities[[tmpV]]$eqSimExp
}
}
#store vsim expressions
tmp_expressions=c(parse(text=paste0('LAST__EVAL__EQ="',tmpVfull,'";')),
tmp_expressions,
parse(text=paste0('if (any(! is.finite(',tmpVfull,'[', model_max_lag_1,',]))) stop(\'Uncomputable solution or numeric overflow while evaluating \"',tmpV,'\".\');')))
#deal with exogenization
if (! tmpVfull %in% names(Exogenize))
{
for (idxSP in 1:actualSimSteps)
{
vsim_expressions[[idxSP]][[idxB]]=c( vsim_expressions[[idxSP]][[idxB]],tmp_expressions)
}
} else
{
for (idxSP in 1:actualSimSteps)
{
if (! idxSP %in% Exogenize[[tmpVfull]]) vsim_expressions[[idxSP]][[idxB]]=c( vsim_expressions[[idxSP]][[idxB]],tmp_expressions)
}
}
#store next vfeed values (we need for convergence test and jacobian)
if (idxE>=vfeedIndexInVsim)
{
tmp_expressions=parse(text=paste0('VFEED__NEXT[',1+idxE-vfeedIndexInVsim,',]=',tmpVfull,'[', model_max_lag_1,',]'))
for (idxSP in 1:actualSimSteps) vsim_expressions[[idxSP]][[idxB]]=c( vsim_expressions[[idxSP]][[idxB]],tmp_expressions)
}
}#end idxE
}
#build vpost expression
if (length_model_vpost[idxB]>0)
{
for (idxI in 1:length(model_vpost[[idxB]]))
{
tmpV=model_vpost[[idxB]][idxI]
#init tmp vars
tmp_expressions=c()
tmpVfull=tmpV
if (hasLeads && simSteps>1 && grepl('__LEAD__',tmpV))
{
tmpV=strsplit(tmpVfull,'__LEAD__')[[1]][1]
#append sim expression
if (tmpV %in% model_names_behavioral)
{
tmp_expressions=model$behaviorals[[tmpV]]$leadsEqSimExp[[tmpVfull]]
} else
{
tmp_expressions=model$identities[[tmpV]]$leadsEqSimExp[[tmpVfull]]
}
} else {
#append sim expression
if (tmpV %in% model_names_behavioral)
{
tmp_expressions=model$behaviorals[[tmpV]]$eqSimExp
} else
{
tmp_expressions=model$identities[[tmpV]]$eqSimExp
}
}
tmp_expressions=c(parse(text=paste0('LAST__EVAL__EQ="',tmpVfull,'";')),
tmp_expressions,
parse(text=paste0('if (any(! is.finite(',tmpVfull,'[', model_max_lag_1,',]))) stop(\'Uncomputable solution or numeric overflow while evaluating \"',tmpV,'\".\');')))
#deal with exogenization
if (! tmpVfull %in% names(Exogenize))
{
for (idxSP in 1:actualSimSteps)
{
vpost_expressions[[idxSP]][[idxB]]=c(vpost_expressions[[idxSP]][[idxB]],tmp_expressions)
}
} else
{
for (idxSP in 1:actualSimSteps)
{
if (! idxSP %in% Exogenize[[tmpVfull]]) vpost_expressions[[idxSP]][[idxB]]=c(vpost_expressions[[idxSP]][[idxB]],tmp_expressions)
}
}
}
}
}#end vblocks for
#set convergence value in local environment
localE$CONVERGENCE__VALUE=simConvergence/100
}#end block simType != RESCHECK
if (simType!='RESCHECK' && length_model_vblocks==0)
.MODEL_outputText(sep='',outputText=!quietly,callerName,'warning, model\'s incidence graph is not cyclic. There is no convergence to be achieved.\n')
# main loop --------------------------------------------------------------
#proxies 4 speedup - ok with leads too
if (STOCHSIMULATE )
noised_vendog=base::intersect(names(StochStructure),model_vendog)
if (OPTIMIZE )
optimized_vendog=base::intersect(names(OptimizeBounds),model_vendog)
tryCatch({
#simrange loop
for (simIterLoopIdx in 1:simSteps)
{
#in leaded model, only the very first period in TSRANGE is evaluated
if (hasLeads && simIterLoopIdx>1) break;
if (! hasLeads)
{
percentageCompletionPorxy=simIterLoopIdx
} else {
percentageCompletionPorxy=0
}
if (MULTMATRIX)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Multiplier Matrix:'),sprintf("%10.2f",percentageCompletionPorxy*100/simSteps),'%')
} else if (STOCHSIMULATE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Stochastic Simulation:'),sprintf("%10.2f",percentageCompletionPorxy*100/simSteps),'%')
} else if (OPTIMIZE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Optimize:'),sprintf("%10.2f",percentageCompletionPorxy*100/simSteps),'%')
} else
{.MODEL_outputText(outputText=!quietly,paste0('\r','Simulation:'),sprintf("%10.2f",percentageCompletionPorxy*100/simSteps),'%') }
#ok with leads too
if (simType != 'RESCHECK' && (verbose)) {cat('\n') }
#create local proxies for all references
#(i.e. components names used in eq) in behaviorals/identities
#in sliding window (with range == maxlag+tsrange) starting from simIterLoopIdx
tempRange=simIterLoopIdx+(0:model_max_lag)
for (idxI in 1:length(model_fullComponentList))
{
tempName=model_fullComponentList[idxI]
localE[[tempName]]=localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]][tempRange,,drop=F]
}
#proxy for explicit constant adjustments
if (length(ConstantAdjustment)>0)
for (idxI in 1:length(CA_names))
{
tempName=CA_names[idxI]
localE[[tempName]]=localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]][tempRange,,drop=F]
}
#proxy for vendog constant adjustment as INSTRUMENT
#vendog can be in INSTRUMENT (e.g. modified endo with SHOCK in MULTMATRIX) but not in CA list
if (length(instrumentVendogs)>0)
for (idxI in 1:length(instrum_names))
{
tempName=instrum_names[idxI]
localE[[tempName]]=localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]][tempRange,,drop=F]
}
#proxy for vendog noised in stochastic simulation
#vendog can be noised (e.g. in StochStructure) but not in CA list
if (STOCHSIMULATE )
{
# if (length(noised_vendog)>0)
{
tempS=paste0(noised_vendog,'__ADDFACTOR')
for (idxI in 1:length(tempS))
{
tempName=tempS[idxI]
localE[[tempName]]=localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]][tempRange,,drop=F]
}
}
}
#proxy for vendog noised in optimize simulation
#vendog can be noised (e.g. in OptimizeBounds) but not in CA list
if (OPTIMIZE )
{
if (length(optimized_vendog)>0)
{
tempS=paste0(optimized_vendog,'__ADDFACTOR')
for (idxI in 1:length(tempS))
{
tempName=tempS[idxI]
localE[[tempName]]=localE[[paste0(tempName,'__ORIGINAL__EXTENDED')]][tempRange,,drop=F]
}
}
}
# check optimize restrictions --------------------------------------------------
if (OPTIMIZE && length(OptimizeRestrictions)>0)
{
for (idxIE in 1:length(OptimizeRestrictions))
{
#check if we are inside restriction tsrange
if ((model_max_lag+simIterLoopIdx) %in% OptimizeRestrictions[[idxIE]]$TSRANGE)
{
tryCatch({
localE$LAST__EVAL__EQ=paste0('OptimizeRestrictions$',names(OptimizeRestrictions)[idxIE])
#eval current restriction using current INSTRUMENT data
currentRestrictionResults=eval(OptimizeRestrictions[[idxIE]]$inExpr,envir=localE)
if (length(currentRestrictionResults)==0 || any(is.na(currentRestrictionResults)) || ! all(is.logical(currentRestrictionResults)))
stop('restriction must be a computable inequality.')
if (length(optColsToBeKept) != length(currentRestrictionResults[-1])) stop('unknown error.')
optColsToBeKept=optColsToBeKept & currentRestrictionResults[-1]
},error=function(err) stop(paste0('Cannot evaluate "OptimizeRestrictions$',
names(OptimizeRestrictions)[idxIE],
'", inequality "',
OptimizeRestrictions[[idxIE]]$INEQUALITY,'": ',err$message))
,warning=function(warn) cat(paste0('\n',callerName,'warning on evaluating "OptimizeRestrictions$',
names(OptimizeRestrictions)[idxIE],': ',warn$message),'\n')
)
}
}
if (hasLeads && simSteps>1)
{
for (idxIE in 1:length(OptimizeRestrictions))
{
eqInExprText=as.character(OptimizeRestrictions[[idxIE]]$inExpr)
#build leaded inequalities
leadedInequalitiesTemp=lapply(.leadEqSim(names(OptimizeRestrictions)[idxIE],
eqInExprText,
model_max_lag_1,
simSteps
),
function(x) parse(text=x))
for (idxSS in 1:(simSteps-1))
{
if ((model_max_lag+idxSS+1) %in% OptimizeRestrictions[[idxIE]]$TSRANGE)
{
tryCatch({
tempName=paste0(names(OptimizeRestrictions)[idxIE],'__LEAD__',idxSS)
localE$LAST__EVAL__EQ=paste0('OptimizeRestrictions$',tempName)
#eval current restriction using current INSTRUMENT data
currentRestrictionResults=eval(leadedInequalitiesTemp[[tempName]],envir=localE)
if (length(currentRestrictionResults)==0 || any(is.na(currentRestrictionResults)) || ! all(is.logical(currentRestrictionResults)))
stop('restriction must be a computable inequality.')
if (length(optColsToBeKept) != length(currentRestrictionResults[-1])) stop('unknown error.')
optColsToBeKept=optColsToBeKept & currentRestrictionResults[-1]
},error=function(err) stop(paste0('Cannot evaluate "OptimizeRestrictions$',
names(OptimizeRestrictions)[idxIE],
'", inequality "',
OptimizeRestrictions[[idxIE]]$INEQUALITY,'": ',err$message))
,warning=function(warn) cat(paste0('\n',callerName,'warning on evaluating "OptimizeRestrictions$',
names(OptimizeRestrictions)[idxIE],': ',warn$message),'\n')
)
}
}
}
}
}#end if optimize
# rescheck loop ---------------------------------------
if (simType=='RESCHECK')
{
#base behaviorals rescheck eval
tryCatch(
{
#cycle behaviorals
if (length(model_names_behavioral)>0)
for (idxI in 1:length(model_names_behavioral))
{
currentVendog=model_names_behavioral[idxI]
#backup historical value
backupVendog=localE[[currentVendog]]
#if not exoginated eval expression
if ( ! ((simIterLoopIdx %in% Exogenize[[currentVendog]])))
{
localE$LAST__EVAL__EQ=currentVendog
eval(model$behaviorals[[currentVendog]]$eqSimExp,envir=localE)
}
#get evaluated current value
tmpResCheck=localE[[currentVendog]][model_max_lag_1,,drop=F]
#restore vendog (could be used in other eqs)
localE[[currentVendog]]=backupVendog
#check missings
localMissingIndexes=any(! is.finite(tmpResCheck))
if (localMissingIndexes)
stop(paste0('Uncomputable solution or numeric overflow in residual checking of behavioral EQ "',
model$behaviorals[[currentVendog]]$eq,
'" in year-period ',paste0(
normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),frequency)
,collapse = '-'),
'.\nCheck equation computability, or lagged time series span.',
ifelse(! is.null(model$behaviorals[[currentVendog]]$errorRaw),paste0('\nBehavioral has "ERROR> ',model$behaviorals[[currentVendog]]$errorRaw,'", that lags the whole equation.'),''),
ifelse(! is.null(model$behaviorals[[currentVendog]]$pdlRaw),paste0('\nBehavioral has "PDL> ',model$behaviorals[[currentVendog]]$pdlRaw,'", that lags the whole regressor.'),'')
))
#append results
simulation[[currentVendog]]=rbind(simulation[[currentVendog]],tmpResCheck)
} #end cycle behaviorals
},error=function(err){
stop(paste0(err$message))}
)#base behavioral rescheck
if (hasLeads && simSteps>1 && length(model_names_behavioral)>0)
{
#leaded behaviorals rescheck eval
tryCatch(
{
#cycle behaviorals
for (idxSS in 1:(simSteps-1)) for (idxI in 1:length(model_names_behavioral) )
{
currentVendog=model_names_behavioral[idxI]
#backup historical value
tempName=paste0(currentVendog,'__LEAD__',idxSS)
backupVendog=localE[[tempName]]
#if not exogenizated eval expression
if ( ! ((simIterLoopIdx %in% Exogenize[[tempName]])))
{
localE$LAST__EVAL__EQ=tempName
eval(model$behaviorals[[currentVendog]]$leadsEqSimExp[[tempName]],envir=localE)
}
#get evaluated current value
tmpResCheck=localE[[tempName]][model_max_lag_1,,drop=F]
#restore vendog (could be used in other eqs)
localE[[tempName]]=backupVendog
#check missings
localMissingIndexes=any(! is.finite(tmpResCheck))
if (localMissingIndexes)
stop(paste0('Uncomputable solution or numeric overflow in residual checking of behavioral EQ "',
model$behaviorals[[currentVendog]]$eq,
'" in year-period ',paste0(
normalizeYP(c(TSRANGE[1],TSRANGE[2]+idxSS),frequency)
,collapse = '-'),
'.\nCheck equation computability, or lagged time series span.',
ifelse(! is.null(model$behaviorals[[currentVendog]]$errorRaw),paste0('\nBehavioral has "ERROR> ',model$behaviorals[[currentVendog]]$errorRaw,'", that lags the whole equation.'),''),
ifelse(! is.null(model$behaviorals[[currentVendog]]$pdlRaw),paste0('\nBehavioral has "PDL> ',model$behaviorals[[currentVendog]]$pdlRaw,'", that lags the whole regressor.'),'')
))
#append results
simulation[[tempName]]=rbind(simulation[[tempName]],tmpResCheck)
}#end cycle behaviorals
},error=function(err){
stop(paste0(err$message))}
)#end trycatch
}#has leads behavioral
#base identity rescheck eval
tryCatch(
{
#cycle identities
if (length(model_names_identity)>0)
for (idxI in 1:length(model_names_identity))
{
currentVendog=model_names_identity[idxI]
#backup historical value
backupVendog=localE[[currentVendog]]
#if not exogenated eval expression
if (!((simIterLoopIdx %in% Exogenize[[currentVendog]])))
{
localE$LAST__EVAL__EQ=currentVendog
eval(model$identities[[currentVendog]]$eqSimExp,envir=localE)
}
#get evaluated current value
tmpResCheck=localE[[currentVendog]][model_max_lag_1,,drop=F]
#restore historical
localE[[currentVendog]]=backupVendog
#check missings
localMissingIndexes=any(! is.finite(tmpResCheck))
if (localMissingIndexes)
stop(paste0('Uncomputable solution or numeric overflow in residual checking of identity EQ "',model$identities[[currentVendog]]$eqFull,
'" in year-period ',paste0(
normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),frequency)
,collapse = '-'),
'.\nCheck equation computability or lagged time series span.'
))
#append results
simulation[[currentVendog]]=rbind(simulation[[currentVendog]],tmpResCheck)
}#for in vendog
},error=function(err){
stop(paste0(err$message))
}
)#base identity rescheck
#leaded identity rescheck eval
if (hasLeads && simSteps>1 && length(model_names_identity)>0)
{
tryCatch(
{
#cycle identities
for (idxSS in 1:(simSteps-1)) for (idxI in 1:length(model_names_identity))
{
currentVendog=model_names_identity[idxI]
#backup historical value
tempName=paste0(currentVendog,'__LEAD__',idxSS)
backupVendog=localE[[tempName]]
#if not exogenated eval expression
if (!((simIterLoopIdx %in% Exogenize[[tempName]])))
{
localE$LAST__EVAL__EQ=tempName
eval(model$identities[[currentVendog]]$leadsEqSimExp[[tempName]],envir=localE)
}
#get evaluated current value
tmpResCheck=localE[[tempName]][model_max_lag_1,,drop=F]
#restore historical
localE[[tempName]]=backupVendog
#check missings
localMissingIndexes=any(! is.finite(tmpResCheck))
if (localMissingIndexes)
stop(paste0('Uncomputable solution or numeric overflow in residual checking of identity EQ "',model$identities[[currentVendog]]$eqFull,
'" in year-period ',paste0(
normalizeYP(c(TSRANGE[1],TSRANGE[2]+idxSS),frequency)
,collapse = '-'),
'.\nCheck equation computability or lagged time series span.'
))
#append results
simulation[[tempName]]=rbind(simulation[[tempName]],tmpResCheck)
}#for in vendog
},error=function(err){
stop(paste0(err$message))
}
)
}#hasleads identities
if (hasLeads)
{
if (MULTMATRIX)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Multiplier Matrix:'),sprintf("%10.2f",100),'%')
} else if (STOCHSIMULATE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Stochastic Simulation:'),sprintf("%10.2f",100),'%')
} else if (OPTIMIZE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Optimize:'),sprintf("%10.2f",100),'%')
} else
{.MODEL_outputText(outputText=!quietly,paste0('\r','Simulation:'),sprintf("%10.2f",100),'%') }
}
if (verbose && verboseSincePeriod<=simIterLoopIdx && length(verboseVars)>0)
{
.printVerboseSim('RESCHECK',
ConstantAdjustment,
verboseVars,
frequency,
TSRANGE,
simSteps,
simIterLoopIdx,
1,
0,
model_max_lag_1,
length_model_vexog,
model_vendog,
model_vexog,
replica,
localE,
model_vpre,
model_vsim,
model_vpost,
hasLeads)
}
}#end is RESCHECK
# convergence loop ------------------------------------------
if (simType != 'RESCHECK')
{
#if FORECAST is requested, value in first iter is set equal to the previously simulated value
#(in first period of TSRANGE we set endo equal to his previous historical value)
if (simType=='FORECAST' && length(model_vendog_no_if)>0)
for (idxI in 1:length(model_vendog_no_if))
{
tempName = (model_vendog_no_if)[idxI]
#if any error we save current vendog name to be printed out in messages
localE$LAST__EVAL__EQ=tempName
#NEEDED...deal with exogenization...
#model_vendog_no_if are endo with no IF... but still can be exogenized
if ((simIterLoopIdx %in% Exogenize[[tempName]])) next
#get vendog values
tmpValues=localE[[tempName]]
#forecast in first period needs previous historical data that can be missing
if (simIterLoopIdx==1 && any(! is.finite(tmpValues[model_max_lag,] )))
stop(callerName,'cannot use FORECAST with endogenous variable "',tempName,'" that has a missing value in its last historical observation prior to TSRANGE.')
#copy previous simulated (historical if first period) to current
tmpValues[ model_max_lag_1,]=tmpValues[model_max_lag,,drop=F]
#update time series
localE[[tempName]]=tmpValues
}
#iterations index
idxIter=0
# eval vpre ------------------------------
#eval vpre expression
eval(vpre_expressions[[simIterLoopIdx]]
,envir=localE
)
#print stuff if required
if (verbose && verboseSincePeriod<=simIterLoopIdx && length(verboseVars)>0)
{
.printVerboseSim('VPRE',
ConstantAdjustment,
verboseVars,
frequency,
TSRANGE,
simSteps,
simIterLoopIdx,
idxB,
idxIter,
model_max_lag_1,
length_model_vexog,
model_vendog,
model_vexog,
replica,
localE,
model_vpre,
model_vsim,
model_vpost,
hasLeads)
}
#flag for convergence
flagConvergence=1
localE$FC__=flagConvergence
if (length_model_vblocks>0) for (idxB in 1:length_model_vblocks)
{
if (hasLeads)
{
if (MULTMATRIX)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Multiplier Matrix:'),sprintf("%10.2f",(idxB-1)*100/length_model_vblocks),'%')
} else if (STOCHSIMULATE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Stochastic Simulation:'),sprintf("%10.2f",(idxB-1)*100/length_model_vblocks),'%')
} else if (OPTIMIZE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Optimize:'),sprintf("%10.2f",(idxB-1)*100/length_model_vblocks),'%')
} else
{.MODEL_outputText(outputText=!quietly,paste0('\r','Simulation:'),sprintf("%10.2f",(idxB-1)*100/length_model_vblocks),'%') }
}
localE$IDXB__=idxB
if ( length_model_vsim[idxB]>0 )
{
flagConvergence=0
localE$FC__=flagConvergence
with(localE,{
MODEL__VFEED=MODEL__VFEED__LIST[[IDXB__]]
LENGTH__MODEL__VFEED=LENGTH__MODEL__VFEED__LIST[IDXB__]
#new feedback values
VFEED__NEXT=matrix(ncol=REPLICA__,nrow=LENGTH__MODEL__VFEED)
#current feedback values
VFEED__CURRENT=VFEED__NEXT
#temp feedback values
VFEED__TEMP=VFEED__NEXT
for (IDXE__ in 1:LENGTH__MODEL__VFEED)
{
#init feedback proxy with historical values (we need it for convergence test)
#during iterations we assign VFEED_CURRENT=VFEED_NEXT
VFEED__NEXT[IDXE__,]=localE[[MODEL__VFEED[IDXE__]]][MODEL__MAX__LAG__1,,drop=F]
}
})
# init jacobian ------------------------------
if (simAlgo!='GAUSS-SEIDEL' )
{
#proxy var to localE
localE$SIM__ITER__LOOP__IDX=simIterLoopIdx
with(localE,{
#reset jacobian
if (! RECALCULATE__JACOBIAN__ARRAY[IDXB__])
{
if (SIM__ALGO=='NEWTON')
{
JACOBIAN__SINGLE__MATRIX__ACTIVE=JACOBIAN__SINGLE__MATRIX__ACTIVE__LIST[[IDXB__]]
} else{#FULLNEWTON
JACOBIAN__FULL__MATRIX__ACTIVE=JACOBIAN__FULL__MATRIX__ACTIVE__LIST[[IDXB__]]
}
}
JACOBIAN__SCALE__VALUE=JACOBIAN__SCALE__VALUE__LIST[[IDXB__]]
#jacobian base line
JACOBIAN__VFEED__BASELINE=matrix(ncol=REPLICA__,nrow=LENGTH__MODEL__VFEED)
JACOBIAN__VFEED__ACTIVE=JACOBIAN__VFEED__ACTIVE__LIST[[IDXB__]]
#init performance parameter
JACOBIAN__RELAX__VALUE=1
JACOBIAN__DMAX__CURRENT=0
JACOBIAN__DMAX__PREV=0
JACOBIAN__RATIO__CURRENT=0.5
JACOBIAN__RATIO__PREV=0
JACOBIAN__GMRRP__=0
#check there are active vfeed
VFEED__ACTIVE__JACOBIAN__IDXS=which(JACOBIAN__VFEED__ACTIVE[,SIM__ITER__LOOP__IDX]==1)
LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS=length(VFEED__ACTIVE__JACOBIAN__IDXS)
if (LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS==0)
{
.MODEL_outputText(outputText=verbose,paste0('\n',callerName,'warning, a "NEWTON" algorithm is requested but all feedback variables have been exogenized or dropped from the Jacobian matrix in simulation period ',SIM__ITER__LOOP__IDX,', year-period ',paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+SIM__ITER__LOOP__IDX-1),f=frequency),collapse='-'),', block ',IDXB__,'.\n'))
} else {
#check if a new Jacobian is required due to new vfeed exogenizations in current period
if(SIM__ITER__LOOP__IDX>1 &&
any(xor(JACOBIAN__VFEED__ACTIVE[,SIM__ITER__LOOP__IDX],JACOBIAN__VFEED__ACTIVE[,SIM__ITER__LOOP__IDX-1]))
)
{
RECALCULATE__JACOBIAN__ARRAY[IDXB__]=TRUE
}
}
})#end with localE
}#end init jacobian
# eval vsim ------------------------------
#main sim stuff... cycle till convergence or max iter limit
#WARNING: THIS FOR-CYCLE MUST BE SUPER FAST
vsim_expressions_local=vsim_expressions[[simIterLoopIdx]][[idxB]]
for (idxIter in 1:simIterLimit)
{
#eval vsim expressions
eval( vsim_expressions_local,envir=localE)
if (simAlgo!='GAUSS-SEIDEL')
{
#proxy vars in localE
localE$IDX__ITER=idxIter
with(localE,{
if (LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS > 0)
{
# evaluate convergence speed --------------------------
#backup current convergence speed indicators
JACOBIAN__DMAX__PREV=JACOBIAN__DMAX__CURRENT
JACOBIAN__DMAX__CURRENT=max(abs(VFEED__NEXT-VFEED__CURRENT))
JACOBIAN__RATIO__PREV=JACOBIAN__RATIO__CURRENT
if (SIM__ALGO=='NEWTON')
{
GMRRP__LIMIT__1=0.9
GMRRP__LIMIT__2=0.75
} else{#FULLNEWTON
GMRRP__LIMIT__1=0.6
GMRRP__LIMIT__2=0.45
}
if (IDX__ITER>1)
{
#recalculate convergence speed indicators
if (JACOBIAN__DMAX__PREV>0) JACOBIAN__RATIO__CURRENT=JACOBIAN__DMAX__CURRENT/JACOBIAN__DMAX__PREV
JACOBIAN__GMRRP__=sqrt(JACOBIAN__RATIO__CURRENT*JACOBIAN__RATIO__PREV)
if (! is.finite(JACOBIAN__GMRRP__)) stop('No convergence, due to numeric overflow in Newton optimization in block ',IDXB__,'.')
#convergence evaluation
if (JACOBIAN__GMRRP__ > GMRRP__LIMIT__1)
{
#convergence is too slow, we need a new Jacobian
RECALCULATE__JACOBIAN__ARRAY[IDXB__]=TRUE
} else if(JACOBIAN__GMRRP__ > GMRRP__LIMIT__2)
{
#convergence is slow, we try to relax vfeed updates
JACOBIAN__RELAX__VALUE=max(JACOBIAN__RELAX__VALUE*0.8,0.5)
}
}
# build jacobian ---------------------------------------
if (RECALCULATE__JACOBIAN__ARRAY[IDXB__]) {
#reset jacobian
if (SIM__ALGO=='NEWTON')
{
.MODEL_outputText(outputText=verbose,paste0('\n',callerName,'building a new Jacobian matrix (',LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS,'x',LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS,') in ',ifelse(hasLeads,'',paste0('simulation period ',simIterLoopIdx,', year-period ',paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),f=frequency),collapse='-'),', ')),'block ',IDXB__,', iteration ',IDX__ITER,'.'))
JACOBIAN__SINGLE__MATRIX=matrix(ncol=LENGTH__MODEL__VFEED,nrow=LENGTH__MODEL__VFEED)
} else{#FULLNEWTON
.MODEL_outputText(outputText=verbose,paste0('\n',callerName,'building a new Jacobian array (',LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS,'x',LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS,'x',REPLICA__,') in ',ifelse(hasLeads,'',paste0('simulation period ',simIterLoopIdx,', year-period ',paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),f=frequency),collapse='-'),', ')),'block ',IDXB__,', iteration ',IDX__ITER,'.'))
JACOBIAN__FULL__MATRIX=array(dim=c(LENGTH__MODEL__VFEED,LENGTH__MODEL__VFEED,REPLICA__))
}
#backup vfeed current
VFEED__CURRENT__BACKUP=VFEED__CURRENT
#log operations in case of error
LAST__EVAL__EQ='Jacobian Base Solution'
#store baseline vfeed value (atm we already have performed one vsim evaluation)
JACOBIAN__VFEED__BASELINE=VFEED__NEXT
#restore ALL vfeed value
#(ALL vfeed changed during last vsim evaluation so ALL must be restored)
for (IDX__ in 1:LENGTH__MODEL__VFEED)
{
localE[[MODEL__VFEED[IDX__]]][MODEL__MAX__LAG__1,]=VFEED__CURRENT__BACKUP[IDX__,]
}
#cycle to vfeed, shock them one by one, re-calculate vsim, then store derivative in jacobian column
for (IDX__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
{
#calculate local shock
TEMP__DELTA=localE[[MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]]]][MODEL__MAX__LAG__1,]*JACOBIAN__SHOCK
TEMP__DELTA[which(abs(TEMP__DELTA)<JACOBIAN__SHOCK)]=JACOBIAN__SHOCK
#shock vfeed IDX__
localE[[MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]]]][MODEL__MAX__LAG__1,]=
TEMP__DELTA+localE[[MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]]]][MODEL__MAX__LAG__1,]
#calculate shocked vsim model
eval( vsim_expressions_local )
#log operations in case of error
LAST__EVAL__EQ='Jacobian Shocked Solution'
#calculate single-jacobian single column (note the 1s on the column indexes)
if (SIM__ALGO=='NEWTON')
{
JACOBIAN__SINGLE__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS,VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]] =
- (
VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,1,drop=F]-
JACOBIAN__VFEED__BASELINE[VFEED__ACTIVE__JACOBIAN__IDXS,1,drop=F]
)/
TEMP__DELTA[1,drop=F]
#deal with principal diagonal
JACOBIAN__SINGLE__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]] =
1 + JACOBIAN__SINGLE__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]]
} else {#FULLNEWTON
#calculate derivatives for all replicas
TEMP__MATRIX = - (
VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]-
JACOBIAN__VFEED__BASELINE[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]
)/
matrix(TEMP__DELTA[,drop=F],nrow=LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS,ncol=REPLICA__,byrow=T)
for (IDX2__ in 1:REPLICA__)
{
#insert values in 3d array JACOBIAN__FULL__MATRIX
JACOBIAN__FULL__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS,VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],IDX2__]=
TEMP__MATRIX[,IDX2__,drop=F]
#deal with principal diagonal
JACOBIAN__FULL__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],IDX2__] =
1 + JACOBIAN__FULL__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],IDX2__]
}
} #end FULLNEWTON
#restore ALL vfeed value
for (IDX2__ in 1:LENGTH__MODEL__VFEED)
{
localE[[MODEL__VFEED[IDX2__]]][ MODEL__MAX__LAG__1,]=VFEED__CURRENT__BACKUP[IDX2__,]
}
}
#restore VFEED__NEXT to old VFEED__CURRENT in order to run again vsim
#(in vsim we init VFEED__CURRENT=VFEED__NEXT)
VFEED__NEXT=VFEED__CURRENT__BACKUP
#recalculate current vsim
#(we need to restore also all vsim not in vfeed)
eval(vsim_expressions_local)
#log operations in case of error
LAST__EVAL__EQ='Jacobian Scaling'
if (SIM__ALGO=='NEWTON')
{
#extract active vfeed
JACOBIAN__SINGLE__MATRIX__ACTIVE=JACOBIAN__SINGLE__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS,VFEED__ACTIVE__JACOBIAN__IDXS,drop=F]
#scale jacobian with current scale value
for (IDX1__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
for (IDX2__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
{
JACOBIAN__SINGLE__MATRIX__ACTIVE[IDX1__,IDX2__]=JACOBIAN__SINGLE__MATRIX__ACTIVE[IDX1__,IDX2__]*
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX2__],1]/
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],1]
}
#check singularities and calculate new scale values
#we try max 10 times to normalize jacobian
for (IDX__ in 1:10)
{
DONE__=TRUE
for (IDX1__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
{
SROW__=sum(JACOBIAN__SINGLE__MATRIX__ACTIVE[IDX1__,]^2)
SCOL__=sum(JACOBIAN__SINGLE__MATRIX__ACTIVE[,IDX1__]^2)
if (!(is.finite(SROW__) && is.finite(SCOL__))) stop('No convergence, due to numeric overflow in Jacobian matrix scaling.')
if (SROW__ < 1e-6 || SCOL__ < 1e-6)
stop(paste0('Jacobian matrix is singular in the variable "',
MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__]],'". Try to drop "',strsplit(MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__]],'__LEAD__')[[1]][1],
'" variable from the Jacobian matrix by using the "JacobianDrop" argument.'))
FAC__=sqrt(sqrt(SROW__ / SCOL__))
if (FAC__ < 0.5 || FAC__ > 2)
{
DONE__=FALSE
JACOBIAN__SINGLE__MATRIX__ACTIVE[IDX1__,]=JACOBIAN__SINGLE__MATRIX__ACTIVE[IDX1__,]/FAC__
JACOBIAN__SINGLE__MATRIX__ACTIVE[,IDX1__]=JACOBIAN__SINGLE__MATRIX__ACTIVE[,IDX1__]*FAC__
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],]=JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],1]*FAC__
if (any(! is.finite(JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],])))
stop('No convergence, due to numeric overflow in Jacobian matrix scaling.')
}
}#end cycle in active vfeed
if (DONE__) break
}#end 10 tries
if (IDX__==10)
.MODEL_outputText(outputText=verbose,paste0('\n',callerName,'warning, 10 iterations not sufficent to normalize the Jacobian matrix in',ifelse(hasLeads,'',paste0(' simulation period ',simIterLoopIdx,', year-period ',paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),f=frequency),collapse='-'),',')),' block ', IDXB__ ,', iteration ',IDX__ITER,'.\n'))
} else {#FULLNEWTON scaling
#extract active vfeed
JACOBIAN__FULL__MATRIX__ACTIVE=JACOBIAN__FULL__MATRIX[VFEED__ACTIVE__JACOBIAN__IDXS,VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]
#scale jacobian with current scale value
for (IDX3__ in 1:REPLICA__)
for (IDX1__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
for (IDX2__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
{
JACOBIAN__FULL__MATRIX__ACTIVE[IDX1__,IDX2__,IDX3__]=JACOBIAN__FULL__MATRIX__ACTIVE[IDX1__,IDX2__,IDX3__]*
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX2__],IDX3__]/
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],IDX3__]
}
#check singularities and calculate new scale values
#we try max 10 times to normalize jacobian
for (IDX__ in 1:10)
{
DONE__=TRUE
for (IDX3__ in 1:REPLICA__)
for (IDX1__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
{
SROW__=sum(JACOBIAN__FULL__MATRIX__ACTIVE[IDX1__,,IDX3__]^2)
SCOL__=sum(JACOBIAN__FULL__MATRIX__ACTIVE[,IDX1__,IDX3__]^2)
if (!(is.finite(SROW__) && is.finite(SCOL__))) stop('No convergence, due to numeric overflow in Jacobian array scaling.')
if (SROW__ < 1e-6 || SCOL__ < 1e-6)
stop(paste0('Jacobian array is singular in the variable "',
MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__]],'". Try to drop "',strsplit(MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__]],'__LEAD__')[[1]][1],
'" variable from the Jacobian array by using the "JacobianDrop" argument.'))
FAC__=sqrt(sqrt(SROW__ / SCOL__))
if (FAC__ < 0.5 || FAC__ > 2)
{
DONE__=FALSE
JACOBIAN__FULL__MATRIX__ACTIVE[IDX1__,,IDX3__]=JACOBIAN__FULL__MATRIX__ACTIVE[IDX1__,,IDX3__]/FAC__
JACOBIAN__FULL__MATRIX__ACTIVE[,IDX1__,IDX3__]=JACOBIAN__FULL__MATRIX__ACTIVE[,IDX1__,IDX3__]*FAC__
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],IDX3__]=JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],IDX3__]*FAC__
if (any(! is.finite(JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS[IDX1__],IDX3__])))
stop('No convergence, due to numeric overflow in Jacobian array scaling.')
}
}#end cycle in active vfeed
if (DONE__) break
}#end 10 tries
}
RECALCULATE__JACOBIAN__ARRAY[IDXB__]=FALSE
}
# eval Jacobian ----------------------------------------
#log operations in case of error
LAST__EVAL__EQ='Jacobian Inversion'
if (SIM__ALGO=='NEWTON')
{
#solve(J,X) works well also with replicas, given J a single Jacobian matrix and X a matrix(vfeed,replica)
VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,]=solve(JACOBIAN__SINGLE__MATRIX__ACTIVE,
(VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]-VFEED__CURRENT[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F])/
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]
)*JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]*
JACOBIAN__RELAX__VALUE+
VFEED__CURRENT[VFEED__ACTIVE__JACOBIAN__IDXS,,drop=F]
} else { #FULLNEWTON
#must avoid drop=T in jacobian array in solve
for (IDX__ in 1:REPLICA__)
VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,IDX__]=solve(JACOBIAN__FULL__MATRIX__ACTIVE[,,IDX__],
(VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,IDX__,drop=F]-VFEED__CURRENT[VFEED__ACTIVE__JACOBIAN__IDXS,IDX__,drop=F])/
JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS,IDX__,drop=F]
)*JACOBIAN__SCALE__VALUE[VFEED__ACTIVE__JACOBIAN__IDXS,IDX__]*
JACOBIAN__RELAX__VALUE+
VFEED__CURRENT[VFEED__ACTIVE__JACOBIAN__IDXS,IDX__]
}
if (any(!is.finite(VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS,]))) stop('No convergence, due to non-finite solution in Jacobian feedback variables update.')
#update active vfeed
for (IDX__ in 1:LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS)
{
localE[[MODEL__VFEED[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__]]]][MODEL__MAX__LAG__1,]=VFEED__NEXT[VFEED__ACTIVE__JACOBIAN__IDXS[IDX__],]
}
}#end length vfeed active
})#end with localE
}
if (verbose && verboseSincePeriod<=simIterLoopIdx && length(verboseVars)>0)
{
.printVerboseSim('VSIM',
ConstantAdjustment,
verboseVars,
frequency,
TSRANGE,
simSteps,
simIterLoopIdx,
idxB,
idxIter,
model_max_lag_1,
length_model_vexog,
model_vendog,
model_vexog,
replica,
localE,
model_vpre,
model_vsim,
model_vpost,
hasLeads)
}
#eval convergence expression
with(localE,{
TMPV__=abs(VFEED__CURRENT)
TMPV__[which(TMPV__<1)]=1
if (max(
abs((VFEED__NEXT - VFEED__CURRENT))
/TMPV__
) < CONVERGENCE__VALUE
)
{
#if convergence...exit loop
FC__=1
}
})
if (localE$FC__==1)
{
flagConvergence=1
break
}
}#main convergence vsim for
#store jacobians proxies
with(localE,{
if ((SIM__ALGO!='GAUSS-SEIDEL') && (LENGTH__VFEED__ACTIVE__JACOBIAN__IDXS > 0) )
{
if (SIM__ALGO=='NEWTON')
{
JACOBIAN__SINGLE__MATRIX__ACTIVE__LIST[[IDXB__]]=JACOBIAN__SINGLE__MATRIX__ACTIVE
} else{#FULLNEWTON
JACOBIAN__FULL__MATRIX__ACTIVE__LIST[[IDXB__]]=JACOBIAN__FULL__MATRIX__ACTIVE
}
JACOBIAN__SCALE__VALUE__LIST[[IDXB__]]=JACOBIAN__SCALE__VALUE
}
})
}# length vsim > 0
# eval vpost ------------------------------
if ( length_model_vpost[idxB]>0 )
{
#eval vpost expressions
eval(vpost_expressions[[simIterLoopIdx]][[idxB]],envir=localE)
if (verbose && verboseSincePeriod<=simIterLoopIdx && length(verboseVars)>0)
{
.printVerboseSim('VPOST',
ConstantAdjustment,
verboseVars,
frequency,
TSRANGE,
simSteps,
simIterLoopIdx,
idxB,
idxIter,
model_max_lag_1,
length_model_vexog,
model_vendog,
model_vexog,
replica,
localE,
model_vpre,
model_vsim,
model_vpost,
hasLeads)
}
}
#...messages
if (flagConvergence==1)
{
if (verbose)
{
if (hasLeads)
{
.MODEL_outputText(outputText = !quietly,paste0('\n',callerName,'convergence reached in block ', idxB, ', iteration ',idxIter,'.\n'))
}
else {
.MODEL_outputText(outputText = !quietly,paste0('\n',callerName,'simulation period ',simIterLoopIdx,', year-period ',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),f=frequency),collapse='-'),', convergence reached in block ', idxB, ', iteration ',idxIter,'.\n'))
}
}
} else
{
if (hasLeads)
{
.MODEL_outputText(outputText = !quietly,paste0('\n',callerName,'warning, in block ',idxB,' no convergence in ',idxIter,' iterations.\n'))
}
else {
.MODEL_outputText(outputText = !quietly,paste0('\n',callerName,'warning, in simulation period ',simIterLoopIdx,', year-period ',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),f=frequency),collapse='-'),', block ',idxB,' no convergence in ',idxIter,' iterations.\n'))
}
}
}#end vblocks for
if (hasLeads)
{
if (MULTMATRIX)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Multiplier Matrix:'),sprintf("%10.2f",100),'%')
} else if (STOCHSIMULATE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Stochastic Simulation:'),sprintf("%10.2f",100),'%')
} else if (OPTIMIZE)
{.MODEL_outputText(outputText=!quietly,paste0('\r','Optimize:'),sprintf("%10.2f",100),'%')
} else
{.MODEL_outputText(outputText=!quietly,paste0('\r','Simulation:'),sprintf("%10.2f",100),'%') }
}
#store simulated values
tmpIdx=simIterLoopIdx+model_max_lag
#actual == original + leaded vendog
actual_model_vendog=model_vendog
if (hasLeads && (simSteps>1))
for (idxSS in 1:(simSteps-1))
actual_model_vendog=c(actual_model_vendog,paste0(model_vendog,'__LEAD__',idxSS))
#export to simulation list
for (idxI in 1:length(actual_model_vendog))
{
currentVendog = (actual_model_vendog)[idxI]
#cycle in endogenous
#get simulated values
tmpValue=localE[[currentVendog]][model_max_lag_1,,drop=F]
#store in simulation list (each row is a sim period)
simulation[[currentVendog]]=rbind(simulation[[currentVendog]],tmpValue)
#if dynamic or forecast sim type is requested
#then store simulated values also as lagged values in ORIGINAL vendogs
if (!hasLeads)
if (simType=='DYNAMIC' || simType=='FORECAST')
{
#get ORIGINAL values
tmpArr=localE[[paste0(currentVendog,'__ORIGINAL__EXTENDED')]]
#insert simulated value
tmpArr[tmpIdx,] = tmpValue
#store in ORIGNAL for next iterations
localE[[paste0(currentVendog,'__ORIGINAL__EXTENDED')]]=tmpArr
}
}#end for save simulate observation
}#not RESCHECK
# deal with optimize function -------------------------------------
if (OPTIMIZE)
{
#time series of OPTIMIZE FUNs results
#must be initialized with NA
#zeros values could provide misleading information
optFunTSRow=rep(NA,replica-1)
#deal with no lead case
for (idxIE in 1:length(OptimizeFunctions))
{
#check if we are inside optimize function tsrange
if ((model_max_lag+simIterLoopIdx) %in% OptimizeFunctions[[idxIE]]$TSRANGE)
{
tryCatch({
#in RESCHECK localE does not contain simulated ts
if (simType=='RESCHECK')
{
#backup env
localE_BK=localE
#store simulated in localE
for (idxI in 1:length(simulation))
{
idxS=names(simulation)[idxI]
#get original endo in localE
tempM=localE[[idxS]]
#check simulated obs are coherent
if ( (simIterLoopIdx != dim(simulation[[idxS]])[1]) ||
(dim(tempM)[2] != dim(simulation[[idxS]])[2] ))
stop('error in adjusting localE in RESCHECK.')
#modify endo obs with simulated
tempM[(model_max_lag+2-simIterLoopIdx) : ( model_max_lag_1),]=simulation[[idxS]]
#assign to localE
localE[[idxS]]=tempM
}
}
#eval OPTIMIZ FUNCTION idxIE in current simIterLoopIdx period
localE$LAST__EVAL__EQ=paste0('OptimizeFunctions$',names(OptimizeFunctions)[idxIE])
currentFunctionResults=eval(OptimizeFunctions[[idxIE]]$funExpr,envir=localE)
if (length(currentFunctionResults)==0) stop('function must be computable.')
if (length(optFunResults) != length(currentFunctionResults[-1])) stop('unknown error.')
#first unperturbed column must be removed
optFunResults=optFunResults + currentFunctionResults[-1]
optFunTSRow=currentFunctionResults[-1]
if (simType=='RESCHECK')
{
#restore env
localE=localE_BK
}
},error=function(err) stop(paste0('Cannot evaluate "OptimizeFunctions$',
names(OptimizeFunctions)[idxIE],
'", FUNCTION definition "',
OptimizeFunctions[[idxIE]]$FUNCTION,'": ',err$message))
,warning=function(warn) cat(paste0('\n',callerName,'warning on evaluating "OptimizeFunctions$',
names(OptimizeFunctions)[idxIE],': ',warn$message),'\n')
)
}#end if inside opt fun tsrange
}#end cycle opt funs
#deal with lead cases
if (hasLeads && simSteps>1)
{
for (idxSS in 1:(simSteps-1))
{
#init leaded optimize function results
assign(paste0('optFunTSRow__LEAD__',idxSS),rep(NA,replica-1))
}
for (idxIE in 1:length(OptimizeFunctions))
{
eqInExprText=as.character(OptimizeFunctions[[idxIE]]$funExpr)
leadedFunExprsTemp=lapply(.leadEqSim(names(OptimizeFunctions)[idxIE],
eqInExprText,
model_max_lag_1,
simSteps
),
function(x) parse(text=x))
for (idxSS in 1:(simSteps-1))
{
#idxSS period of simulation tsrange is in optimize function tsrange
if ((model_max_lag+idxSS+1) %in% OptimizeFunctions[[idxIE]]$TSRANGE)
{
tryCatch({
#in RESCHECK localE does not contain simulated ts
if (simType=='RESCHECK')
{
#backup env
localE_BK=localE
#store simulated in localE
for (idxI in 1:length(simulation))
{
idxS=names(simulation)[idxI]
#get original endo in localE
tempM=localE[[idxS]]
#check simulated obs are coherent
if ( (simIterLoopIdx != dim(simulation[[idxS]])[1]) ||
(dim(tempM)[2] != dim(simulation[[idxS]])[2] ))
stop('error in adjusting localE in RESCHECK.')
#modify endo obs with simulated
tempM[(model_max_lag+2-simIterLoopIdx) : ( model_max_lag_1),]=simulation[[idxS]]
#assign to localE
localE[[idxS]]=tempM
}
}
#get name of leaded opt fun
tempName=paste0(names(OptimizeFunctions)[idxIE],'__LEAD__',idxSS)
#eval OPTIMIZ FUNCTION idxIE in current simIterLoopIdx period
localE$LAST__EVAL__EQ=paste0('OptimizeFunctions$',tempName)
currentFunctionResults=eval(leadedFunExprsTemp[[tempName]],envir=localE)
if (length(currentFunctionResults)==0 ) stop('function must be computable.')
if (length(optFunResults) != length(currentFunctionResults[-1])) stop('unknown error.')
#first unperturbed column must be removed
optFunResults=optFunResults + currentFunctionResults[-1]
assign(paste0('optFunTSRow__LEAD__',idxSS),currentFunctionResults[-1])
if (simType=='RESCHECK')
{
#restore env
localE=localE_BK
}
},error=function(err) stop(paste0('Cannot evaluate "OptimizeFunctions$',
names(OptimizeFunctions)[idxIE],
'", FUNCTION definition "',
OptimizeFunctions[[idxIE]]$FUNCTION,'": ',err$message))
,warning=function(warn) cat(paste0('\n',callerName,'warning on evaluating "OptimizeFunctions$',
names(OptimizeFunctions)[idxIE],': ',warn$message),'\n')
)
}
}
}
}#hasLeads
#build OPTIMIZE FUNs ts by rbind
optFunTSMM=rbind(optFunTSMM,optFunTSRow)
#build TSMM in lead cases
if (hasLeads && simSteps>1)
{
for (idxSS in 1:(simSteps-1))
{
optFunTSMM=rbind(optFunTSMM,get(paste0('optFunTSRow__LEAD__',idxSS)))
}
}
rownames(optFunTSMM)=NULL
}#end if optimize
}#main cycle
# simulate error message -----------------------------------------------
},error=function(err)
{
#intercept sim algo errors
if (!exists('idxIter')) idxIter=0
if (!exists('idxB')) idxB=0
if (!exists('simIterLoopIdx')) simIterLoopIdx=1
if (verbose && length(verboseVars)>0)
{
.printVerboseSim('ERROR',
ConstantAdjustment,
verboseVars,
frequency,
TSRANGE,
simSteps,
simIterLoopIdx,
idxB,
idxIter,
model_max_lag_1,
length_model_vexog,
model_vendog,
model_vexog,
replica,
localE,
model_vpre,
model_vsim,
model_vpost,
hasLeads)
}
if (hasLeads && simSteps>1)
{
#if error and leads extract varName from varName_LEAD_x
if (grepl('__LEAD__',localE$LAST__EVAL__EQ))
{
tempSplit=strsplit(localE$LAST__EVAL__EQ,'__LEAD__')[[1]]
lastEqLogOut=tempSplit[1]
simIterLoopIdx=as.integer(tempSplit[2])+1
} else {
lastEqLogOut=localE$LAST__EVAL__EQ
simIterLoopIdx=1
}
} else {
simIterLogOut=simIterLoopIdx
lastEqLogOut=localE$LAST__EVAL__EQ
}
stop(paste0('\n',callerName,'error in simulation of type "',simType,'", ','simulation period ',simIterLoopIdx,', year-period ',
paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]+simIterLoopIdx-1),f=frequency),collapse='-'),
', ','block ', idxB ,', iteration ',idxIter,', while evaluating "',
lastEqLogOut,'".\n',err$message,
ifelse(quietly==FALSE,'','\nHint: disable "quietly" in order to get insights on lagged missings that could impact on computation.'),
ifelse(simType !='RESCHECK','\nHint: try a "RESCHECK" simulation in order to check equations definition and computability.',''),
ifelse(replica==1 && simType !='RESCHECK' && simAlgo =='GAUSS-SEIDEL','\nHint: try the "NEWTON" simulation algorithm.',''),
ifelse(verbose==TRUE,'','\nHint: enable "verbose" in order to get more details.'),
ifelse(STOCHSIMULATE,'\nHint: in STOCHSIMULATE() each realization must be computable in order to avoid errors.',''),
ifelse(OPTIMIZE,'\nHint: in OPTIMIZE() each realization must be computable in order to avoid errors.','')
))
})
# post SIMULATE -------------------------------------------------------------
#deal with lead rbind
if (length(simulation)>0)
{
#row bind leaded variables back to original one
if (hasLeads && simSteps>1)
{
for ( idxI in 1:length(model_vendog))
{
vendogName=model_vendog[idxI]
for (idxSS in 1:(simSteps-1))
{
simulation[[vendogName]]=rbind(simulation[[vendogName]],simulation[[paste0(vendogName,'__LEAD__',idxSS)]])
simulation[[paste0(vendogName,'__LEAD__',idxSS)]]=NULL
}
}
}
}
# build MULT MATRIX ------------------------------------------------------------
if (MULTMATRIX==TRUE)
{
#restore original INSTRUMENT
if (hasLeads && simSteps>1)
{
for (idxI in 1:length(INSTRUMENT))
{
idxN=INSTRUMENT[idxI]
for (idxSS in 1:(simSteps-1))
{
#deal with leads
#row bind leaded variables back to original one
localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]]=rbind(localE[[paste0(idxN,'__ORIGINAL__EXTENDED')]],
localE[[paste0(idxN,'__LEAD__',idxSS)]][model_max_lag_1,,drop=F])
localE[[paste0(idxN,'__LEAD__',idxSS)]]=NULL
}
}
}
lenT=length(TARGET)
lenI=length(INSTRUMENT)
MultiplierMatrix=matrix(nrow=lenT*simSteps,
ncol=lenI*simSteps)
#assign names to column
tmpColNames=vector('character',length=simSteps*lenI)
tmpI=0
for (idxIS in 1:simSteps)
{
for (idxI in 1:lenI)
{
tmpI=tmpI+1
tmpColNames[tmpI]=paste0(INSTRUMENT[idxI],'_',idxIS)
}
}
#assign names to rows
tmpRowNames=vector('character',length=simSteps*lenT)
tmpI=0
for (idxTS in 1:simSteps)
{
for (idxT in 1:lenT)
{
tmpI=tmpI+1
tmpRowNames[tmpI]=paste0(TARGET[idxT],'_',idxTS)
}
}
colnames(MultiplierMatrix)=tmpColNames
rownames(MultiplierMatrix)=tmpRowNames
tmpIA=list()
for (idxI in 1:lenI)
{
tmpIA[[idxI]]=localE[[paste0(INSTRUMENT[[idxI]],'__ORIGINAL__EXTENDED')]]
}
#build matrix MM
for (idxT in 1:lenT)
{
tmpT=simulation[[TARGET[idxT]]]
for (idxTS in 1:simSteps)
{
rowMM=idxT+(idxTS-1)*lenT
for (idxI in 1:lenI)
{
tmpI=tmpIA[[idxI]]
colTbase=1+(idxI-1)*simSteps
for (idxIS in 1:simSteps)
{
colT=colTbase+idxIS
dy=tmpT[idxTS,colT]-tmpT[idxTS,1]
rowI=model_max_lag+idxIS
colI=1+(idxI-1)*simSteps+idxIS
dx=tmpI[rowI,colT]-tmpI[rowI,1]
colMM=idxI+(idxIS-1)*lenI
#dx cannot be 0 because of shocks
if (dy==0)
{MultiplierMatrix[rowMM,colMM]=0} else {MultiplierMatrix[rowMM,colMM]=dy/dx}
}
}
}
}
model$MultiplierMatrix=MultiplierMatrix
}
.MODEL_outputText(outputText=!quietly,'\n')
#convert results to time series if replica==1
if (length(simulation)>0)
{
if (replica==1)
{
for (idxSL in 1:length(simulation))
{
simulation[[idxSL]]=TSERIES(simulation[[idxSL]],
START=TSRANGE[1:2],
FREQ=frequency)
}
} else
{
#if MULTMATRIX keep as simulation the first column (the unperturbed one)
if (MULTMATRIX)
{
#store simulation list as matrix in model
simulation_MM=simulation
for (idxSL in 1:length(simulation))
{
simulation[[idxSL]]=TSERIES(simulation[[idxSL]][,1],
START=TSRANGE[1:2],
FREQ=frequency)
}
}#end multmatrix
if (STOCHSIMULATE)
{
if (hasLeads && simSteps>1)
{
for (idxI in 1:length(StochStructure))
{
idxN=names(StochStructure)[idxI]
for (idxSS in 1:(simSteps-1))
{
#deal with leads
#row bind leaded variables back to original one
INSTRUMENT_MM[[idxN]]=rbind(INSTRUMENT_MM[[idxN]],INSTRUMENT_MM[[paste0(idxN,'__LEAD__',idxSS)]])
INSTRUMENT_MM[[paste0(idxN,'__LEAD__',idxSS)]]=NULL
}
}
}
#store simulation list as matrix in model
simulation_MM=simulation
stochastic_simulation=list()
for (idxI in 1:length(simulation))
{
idxSL=names(simulation)[idxI]
simulation[[idxSL]]=TSERIES(simulation_MM[[idxSL]][,1],
START=TSRANGE[1:2],
FREQ=frequency)
#mean all rows but first (not noised)
stochastic_simulation[[idxSL]]=list()
stochastic_simulation[[idxSL]]$mean=TSERIES(rowMeans(simulation_MM[[idxSL]][,-1,drop=F]),
START=TSRANGE[1:2],
FREQ=frequency)
#sd all rows but first
stochastic_simulation[[idxSL]]$sd=TSERIES(apply(simulation_MM[[idxSL]][,-1,drop=F],1,sd),
START=TSRANGE[1:2],
FREQ=frequency)
}
}#end if stochmiulation
if (OPTIMIZE)
{
if (hasLeads && simSteps>1 && length(OptimizeBounds)>0)
{
for (idxI in 1:length(OptimizeBounds))
{
idxN=names(OptimizeBounds)[idxI]
for (idxSS in 1:(simSteps-1))
{
#deal with leads
#row bind leaded variables back to original one
INSTRUMENT_MM[[idxN]]=rbind(INSTRUMENT_MM[[idxN]],INSTRUMENT_MM[[paste0(idxN,'__LEAD__',idxSS)]])
INSTRUMENT_MM[[paste0(idxN,'__LEAD__',idxSS)]]=NULL
}
}
}
#store simulation list as matrix in model
simulation_MM=simulation
optimize=list()
optimize$modelData=model$modelData
optimize$ConstantAdjustment=ConstantAdjustment
for (idxI in 1:length(simulation))
{
idxSL=names(simulation)[idxI]
simulation[[idxSL]]=TSERIES(simulation_MM[[idxSL]][,1],
START=TSRANGE[1:2],
FREQ=frequency)
}
if (length(optColsToBeKept) != length(optFunResults)) stop(callerName,' length mismatch in optimize function results.')
#deal with uncomputable objective function
#realizations could verify restriction but fail in objective function computability,
#so remove realizations not computable in objective functions too
optColsToBeKept=optColsToBeKept & is.finite(optFunResults)
optColsToBeKeptCount=length(which(optColsToBeKept))
#proxy optimize function results
optFunResultsFiltered=optFunResults
optFunResultsFiltered[!optColsToBeKept]=NA
#init max and which.max and stats
optFunMax=NULL
optFunMaxIdx=NULL
optFunAve=NULL
optFunSd=NULL
#init list of opt instruments
OPT_INSTRUMENT=list()
if ( optColsToBeKeptCount > 0)
{
if (! quietly) cat(callerName,'',optColsToBeKeptCount,' out of ',replica-1,
' objective function realizations (',format(round(optColsToBeKeptCount*100/(replica-1),0),nsmall=0),'%) are finite',ifelse(length(OptimizeRestrictions)>0,' and verify the provided restrictions',''),'.\n',sep='')
#get max value
optFunMax=max(optFunResultsFiltered,na.rm=TRUE)
optFunMaxIdx=which.max(optFunResultsFiltered)
#get mean and sd
optFunAve=base::mean(optFunResultsFiltered,na.rm=TRUE)
optFunSd=stats::sd(optFunResultsFiltered,na.rm=TRUE)
#get instruments that allow OPTIMIZE FUNs to be maximized
if (length(OptimizeBounds)>0)
for (idx in 1:length(OptimizeBounds))
{
idxI=names(OptimizeBounds)[idx]
#get original instrument
if (idxI %in% model_vexog)
{
tempINST=localE[[paste0(idxI,'__ORIGINAL__EXTENDED')]]
}
else if (idxI %in% model_vendog)
{
tempINST=localE[[paste0(idxI,'__ADDFACTOR','__ORIGINAL__EXTENDED')]]
} else {
stop(callerName,'error in "optimize$INSTRUMENT" definition. "',idxI,'" is not a model variable.')
}
#get column in optFunMaxIdx position
tempINSTcol=tempINST[,optFunMaxIdx+1]
#export opt instrument (remove pre-TSRANGE obs)
OPT_INSTRUMENT[[idxI]]=TSERIES(tempINSTcol[(model_max_lag_1):length(tempINSTcol)],
START=TSRANGE[1:2],FREQ=frequency)
#get leaded maximing instrument
if (hasLeads && simSteps>1)
{
for (idxSS in 1:(simSteps-1))
{
#get leaded instrument
if (idxI %in% model_vexog)
{
tempINST=localE[[paste0(idxI,'__LEAD__',idxSS)]]
}
else if (idxI %in% model_vendog)
{
tempINST=localE[[paste0(idxI,'__ADDFACTOR','__LEAD__',idxSS)]]
} else {
stop(callerName,'error in "optimize$INSTRUMENT" definition. "',idxI,'" is not a model variable.')
}
#get column in optFunMaxIdx position
tempINSTcol=tempINST[,optFunMaxIdx+1]
#export leaded optimize instrument (remove pre-TSRANGE obs) into original var
tempStart=normalizeYP(c(TSRANGE[1],TSRANGE[2]+idxSS),frequency)
OPT_INSTRUMENT[[idxI]][[tempStart[1],tempStart[2]]]=tempINSTcol[model_max_lag_1]
}
}
#build modelData and ConstantAdj that allow fun maximum
#merge selected instrument obs in TSRANGE with his historical data
if (idxI %in% model_vexog)
{
optimize$modelData[[idxI]]=TSMERGE(OPT_INSTRUMENT[[idxI]],optimize$modelData[[idxI]])
}
else if (idxI %in% model_vendog)
{
#if instrument is endo we use the add-factor (that can be not in CA)
if (is.null(optimize$ConstantAdjustment[[idxI]]))
{
optimize$ConstantAdjustment[[idxI]]=OPT_INSTRUMENT[[idxI]]
} else {
optimize$ConstantAdjustment[[idxI]]=TSMERGE(OPT_INSTRUMENT[[idxI]],optimize$ConstantAdjustment[[idxI]])
}
} else {
stop(callerName,'error in "optimize$modelData" definition. "',idxI,'" is not a model variable.')
}
}
#create TS with maximum OPTIMIZE FUNs realizations obs
optFunTS =TSERIES(optFunTSMM[,optFunMaxIdx],
START=TSRANGE[1:2],
FREQ=frequency)
} else {
if (! quietly) cat(callerName,'warning, none of the computed realizations are finite and verify the provided restrictions. Try to review inequalities and objective functions definition or try to increase the "StochReplica" argument value. OPTIMIZE() will exit with no solution.\n',sep='')
}
#export stuff
#(modelData and ConstantAdjustment already exported)
optimize$optFunResults=optFunResults
optimize$realizationsToKeep=optColsToBeKept
optimize$optFunMax=optFunMax
optimize$INSTRUMENT=OPT_INSTRUMENT
optimize$optFunTS=optFunTS
optimize$optFunSd=optFunSd
optimize$optFunAve=optFunAve
}#end optimize
}#end replica > 1
# build add-factor -------------------------------------
if (simType=='RESCHECK')
{
#should never happen
if (length(setdiff(names(simulation),names(model$modelData)))>0)
stop(callerName,'unknown error in building ConstantAdjustmentRESCHECK list.')
ConstantAdjustmentRESCHECK=list()
if (replica==1)
{
tryCatch({
for (idxCA in names(simulation))
{
if (idxCA %in% names(model$behaviorals))
{
funName=model$behaviorals[[idxCA]]$lhsFun$funName
args=model$behaviorals[[idxCA]]$lhsFun$args
} else
{
funName=model$identities[[idxCA]]$multipleLhsFun[[1]]$funName
args=model$identities[[idxCA]]$multipleLhsFun[[1]]$args
}
if (funName =='LOG' )
{
ConstantAdjustmentRESCHECK[[idxCA]]=log(model$modelData[[idxCA]])-log(simulation[[idxCA]])
} else if ( funName=='EXP' )
{
ConstantAdjustmentRESCHECK[[idxCA]]=exp(model$modelData[[idxCA]])-exp(simulation[[idxCA]])
} else if ( funName=='TSDELTAP' )
{
localLag=1
if (length(args)>1) localLag=as.numeric(args[2])
ConstantAdjustmentRESCHECK[[idxCA]]=100*(model$modelData[[idxCA]]-simulation[[idxCA]])/TSLAG(model$modelData[[idxCA]],localLag)
} else if ( funName=='TSDELTALOG' )
{
localLag=1
if (length(args)>1) localLag=as.numeric(args[2])
ConstantAdjustmentRESCHECK[[idxCA]]=log(model$modelData[[idxCA]]/simulation[[idxCA]])
} else {
ConstantAdjustmentRESCHECK[[idxCA]]=model$modelData[[idxCA]]-simulation[[idxCA]]
}
}
},error=function(err){stop(callerName,'error in building ConstantAdjustmentRESCHECK list in behavioral "',idxCA, '". ',err)}) #trycatch
#merge past add-factors if any
model$ConstantAdjustmentRESCHECK=.combineList(model$ConstantAdjustmentRESCHECK,ConstantAdjustmentRESCHECK)
}
}
}#length(simulation)>0
# backfill -----------------------------------------------
#deal with backfill
if (BackFill>0 )
{
.MODEL_outputText(outputText = !quietly,paste0('\n',callerName,'"BackFill" enabled.\nSolutions will include up to ',BackFill,' periods (if available) of historical data starting in year-period ',paste0(normalizeYP(c(TSRANGE[1],TSRANGE[2]-BackFill),frequency),collapse = '-'),'\n'))
#extend simulation
if (length(simulation)>0)
for (idxI in 1:length(simulation))
{
idxRC=names(simulation)[idxI]
#get original time series
originalTs=model$modelData[[idxRC]]
#get original start
outTSL=TSLOOK(originalTs)
originalStart=c(outTSL$STARTY,outTSL$STARTP)
#get max between requested and available observations
periodsToAdd=min(NUMPERIOD(originalStart,TSRANGE[1:2],frequency),BackFill)
if (periodsToAdd<1) next
#get new starting point
newStart=normalizeYP(c(TSRANGE[1],TSRANGE[2]-periodsToAdd),frequency)
#get extra values
newStaringIndex=1+NUMPERIOD(originalStart,newStart,frequency)
extraValues=coredata(originalTs[newStaringIndex:(newStaringIndex-1+periodsToAdd)])
#save result
simulation[[idxRC]]=TSERIES(c(extraValues,coredata(simulation[[idxRC]]))
,START=newStart,FREQ=frequency)
}
}
#merge past simulations if any
model$simulation=.combineList(model$simulation,simulation)
if (STOCHSIMULATE)
{
model$simulation_MM=.combineList(model$simulation_MM,simulation_MM)
model$INSTRUMENT_MM=.combineList(model$INSTRUMENT_MM,INSTRUMENT_MM)
model$stochastic_simulation=.combineList(model$stochastic_simulation,stochastic_simulation)
}
if (OPTIMIZE)
{
model$simulation_MM=.combineList(model$simulation_MM,simulation_MM)
model$INSTRUMENT_MM=.combineList(model$INSTRUMENT_MM,INSTRUMENT_MM)
model$optimize=optimize
}
#export simulation parameters
model$simulation[['__SIM_PARAMETERS__']]$TSRANGE=TSRANGE
model$simulation[['__SIM_PARAMETERS__']]$simType=simType
model$simulation[['__SIM_PARAMETERS__']]$simConvergence=simConvergence
model$simulation[['__SIM_PARAMETERS__']]$simIterLimit=simIterLimit
model$simulation[['__SIM_PARAMETERS__']]$ZeroErrorAC=ZeroErrorAC
model$simulation[['__SIM_PARAMETERS__']]$BackFillBackFill
model$simulation[['__SIM_PARAMETERS__']]$Exogenize=Exogenize_original
model$simulation[['__SIM_PARAMETERS__']]$ConstantAdjustment=ConstantAdjustment
model$simulation[['__SIM_PARAMETERS__']]$MULTMATRIX=MULTMATRIX
model$simulation[['__SIM_PARAMETERS__']]$TARGET=TARGET
model$simulation[['__SIM_PARAMETERS__']]$INSTRUMENT=INSTRUMENT
model$simulation[['__SIM_PARAMETERS__']]$MM_SHOCK=MM_SHOCK
model$simulation[['__SIM_PARAMETERS__']]$RESCHECKeqList=RESCHECKeqList
if (simType=='DYNAMIC' && hasLeads)
{
model$simulation[['__SIM_PARAMETERS__']]$vblocks=model_vblocks
model$simulation[['__SIM_PARAMETERS__']]$vpre=model_vpre
model$simulation[['__SIM_PARAMETERS__']]$incidence_matrix=incidence_matrix
}
if (STOCHSIMULATE)
{
model$stochastic_simulation[['__STOCH_SIM_PARAMETERS__']]$STOCHSIMULATE=STOCHSIMULATE
model$stochastic_simulation[['__STOCH_SIM_PARAMETERS__']]$StochStructure=StochStructure_original
model$stochastic_simulation[['__STOCH_SIM_PARAMETERS__']]$StochReplica=StochReplica
model$stochastic_simulation[['__STOCH_SIM_PARAMETERS__']]$StochSeed=StochSeed
}
if (OPTIMIZE)
{
model$optimize[['__OPT_PARAMETERS__']]$OPTIMIZE=OPTIMIZE
model$optimize[['__OPT_PARAMETERS__']]$StochReplica=StochReplica
model$optimize[['__OPT_PARAMETERS__']]$StochSeed=StochSeed
model$optimize[['__OPT_PARAMETERS__']]$OptimizeBounds=OptimizeBounds
model$optimize[['__OPT_PARAMETERS__']]$OptimizeRestrictions=OptimizeRestrictions_original
model$optimize[['__OPT_PARAMETERS__']]$OptimizeFunctions=OptimizeFunctions
}
if (MULTMATRIX)
{.MODEL_outputText(outputText=!quietly,'...MULTMATRIX OK\n')
} else if (STOCHSIMULATE)
{.MODEL_outputText(outputText=!quietly,'...STOCHSIMULATE OK\n')
} else if (OPTIMIZE)
{.MODEL_outputText(outputText=!quietly,'...OPTIMIZE OK\n')
} else
{.MODEL_outputText(outputText=!quietly,'...SIMULATE OK\n') }
},error=function(e) {
setBIMETSconf('BIMETS_CONF_NOC', complianceStatus, suppressOutput=TRUE);stop(e)
}) #end main tryCatch for compliance speedup
#reset compliance status
setBIMETSconf('BIMETS_CONF_NOC', complianceStatus, suppressOutput=TRUE)
return(model)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.