#include #include #include #import #include #import #include "simulation.ox" #import /* ------------------------------------------------------ FEM Project Library (Class) The program contains all functions used in the FEM under a class. Uses ModelBaseMPI, which is ModelBase class where I loaded MPI and used it for optimization. Here each processor computes a numerical gradient (with respect to one parameter) and sends back result to master To install on another machine oxmpi will need to be reinstalled by Pierre-Carl Michaud and Yuhui Zheng Last version: September 2008 ------------------------------------------------------*/ // These are model types, only M_INIT should be of interest enum{M_INIT,M_TRANS,M_HYPER} // These are the group of variables, see est_init.ox to understand enum{Y_VAR,W_VAR,Z_VAR,L_VAR,F_VAR,G_VAR} // Types of variables enum{BIN,CONT,ORDER,CENSOR,CENSORBIN,CENSORORDER} // Type of standard errors enum{HESSIAN,OGP} // various stats that can be compiled from data enum{MEAN,SUM,MEDIAN,VAR,PROD} // Type of duration model (for transition model enum{PH,NORMAL,LOGIT} /*------------------ FEM : ModelBaseMPI ------------------*/ // Class definition class FEM : ModelBaseMPI { // vectors and identifiers decl m_vI,m_vT,m_vN,m_vPer; // ids vectors decl m_sI,m_sT,m_sPer; // Names if Ids decl m_cN,m_cNT,m_cPmax,m_cPmin; // # obs and max # periods decl m_cE,m_cD,m_cJ,m_cPer,m_cR; // # dimension if MPH decl m_iModel,m_iResultm_sName,m_asSelect; // Tag for Model Selection decl m_mY,m_mX,m_mZ,m_mL,m_mF,m_mW,m_mG,m_vS; // data of ys and xs decl m_asX,m_asY,m_asL,m_asZ,m_asF,m_asW, m_asG,m_asC,m_vType,m_vThres; // Names of Xs decl m_cX,m_cY,m_cL,m_cF,m_cZ,m_cW,m_cPar,m_cG,m_vM; decl m_mCholeski; decl m_cFactor; // Dim of data decl m_iStdErr,m_iH; decl m_mU; decl m_asParTypes; decl m_asRestrictions,m_cRestrictions,m_iName; //matrices of draws FEM(); // constructor // ------------- Estimation Functions ---------------- ClearEstimation(); ClearModel(); GetcT(); GetModel(); GetPackageName(); GetPackageVersion(); GetParNames(); SetId(const sI, const sT, const sP); SetModel(const iModel); SetDraws(const cR); SetVarType(const vType); SetPath(const spath); SetHazard(const iHazard); GetHazard(const vX); fMapFreetoPar(const vFreePar); SetVerbose(const iVerbose); OutputMax(const sMethod, const iResult, const vPstart, const bNumerical); OutputPar(); OutputLogLik(); OutputHeader(const sTitle); Output(); SavePar(const vFreePar); CalcDraws(); fnGradient(const fnF,const vX0, vF0); SetSelectionVars(const asNames); DropVars(const asY) ; Collapse(const vX, const vI, const iStat, const iLong); SetName(const iName); SetFactor(const num); // ModelBase modified functions (for Estimation) InitPar(); // initialize parameters InitData(); // initialize data Estimate(); // Estimation DoEstimation(vStart); // do the maximation Covar(); // compute variance-covariance matrix SetStd(const is); // Likelihoods fm_init(const vP, const adFunc, const avScore, const amHess); fm_trans(const vP, const adFunc, const avScore, const amHess); // Individual Likelihoods fm_initi(const vP, const adFunc, const avScore, const amHess); fm_transi(const vP, const adFunc, const avScore, const amHess); }; /*----------------- END FEM : ModelBaseMPI ------------------*/ FEM::FEM() // Constructor Function { ModelBaseMPI(); // initialize base class // Set defaults here m_cN = m_cNT = m_cPmax = .NaN; m_asRestrictions = new array[50]; m_cRestrictions = 0; m_mCholeski = 0; SetPath("~"); } /*************************************************************/ /*--------------- ESTIMATION FUNCTIONS ----------------------*/ /*************************************************************/ FEM::ClearModel() { ModelBaseMPI::ClearModel(); } FEM::ClearEstimation() { ModelBaseMPI::ClearEstimation(); } FEM::GetPackageName() { return "Future Elderly Model: Estimation"; } FEM::GetPackageVersion() { return "1.0"; } FEM::SetPath(const spath) { chdir(spath); } FEM::SetName(const iName) { m_iName = iName; } FEM::SetFactor(const num) { m_cFactor = num; } FEM::SetId(const sI, const sT, const sP) { m_sI = sI; m_vI = GetVar(m_sI); m_cNT = sizer(m_vI); m_vN = distincval(m_vI,0); m_cN = sizer(m_vN); m_sT = sT; m_vT = GetVar(m_sT); m_sPer = sP; m_vPer = GetVar(m_sPer); m_cPmax = maxc(m_vPer); m_cPmin = minc(m_vPer); m_cPmax = 1; m_cPer = range(1,m_cPmax,1)'; } FEM::SetDraws(const cR) { m_cR = cR; } FEM::SetVarType(const vType) { m_vType = vType; m_vM = new matrix[6][1]; m_vM[0] = sumc(m_vType.==BIN); m_vM[1] = sumc(m_vType.==CONT); m_vM[2] = sumc(m_vType.==ORDER); m_vM[3] = sumc(m_vType.==CENSOR); m_vM[4] = sumc(m_vType.==CENSORBIN); m_vM[5] = sumc(m_vType.==CENSORORDER); } FEM::SetStd(const is) { m_iStdErr = is; } FEM:: SetHazard(const iHazard) { m_iH = iHazard; } FEM:: GetHazard(const vX) { if (m_iH==NORMAL) return probn(vX); if (m_iH==PH) return 1-exp(-exp(vX)); if (m_iH==LOGIT) return (1+exp(-vX)).^-1; } FEM::SetModel(const iModel) { ClearModel(); m_iModel = iModel; if (GetModelStatus()>MS_DATA) SetModelStatus(MS_DATA); } FEM::GetModel() { if (m_iModel==M_INIT) { return "Initial Condition Model"; } if (m_iModel==M_TRANS) { return "Transition Model"; } } FEM:: fnGradient(const fnF,const vX0, vF0) { decl dEps,vF1,vF2,dN,vE,vEi,mG,dh, bUseTwoSided=FALSE; dEps = 1e-7; dN = rows(vX0); vE = zeros(dN,1); if (vF0==0) fnF(vX0,&vF0,0,0); /* Compute function only if not supplied in argument */ mG = zeros(sizerc(vF0),dN); /* Create a matrix of zeros to store */ /* the first derivatives df(x0)/dx_i */ for (decl i=0;i) { vXm |= ones(sizer(data),1).*meanc(deleter(data)); } else { vXm |= constant(0,sizer(data),1); } } } else { for (decl i = 0 ; i < N; ++i) { data = selectifr(vX,vI.==vN[i]); if (deleter(data)!=<>) { vXm |= meanc(deleter(data)); } else { vXm |= constant(0,1,1); } } } } if (iStat==SUM) { if (iLong==TRUE) { for (decl i = 0 ; i < N; ++i) { data = selectifr(vX,vI.==vN[i]); if (deleter(data)!=<>) { vXm |= ones(sizer(data),1).*sumc(deleter(data)); } else { vXm |= constant(0,sizer(data),1); } } } else { for (decl i = 0 ; i < N; ++i) { data = selectifr(vX,vI.==vN[i]); if (deleter(data)!=<>) { vXm |= sumc(deleter(data)); } else { vXm |= constant(0,1,1); } } } } if (iStat==PROD) { if (iLong==TRUE) { for (decl i = 0 ; i < N; ++i) { data = selectifr(vX,vI.==vN[i]); if (deleter(data)!=<>) { vXm |= ones(sizer(data),1).*prodc(deleter(data)); } else { vXm |= constant(1,sizer(data),1); } } } else { for (decl i = 0 ; i < N; ++i) { data = selectifr(vX,vI.==vN[i]); if (deleter(data)!=<>) { vXm |= prodc(deleter(data)); } else { vXm |= constant(1,1,1); } } } } return dropr(vXm,0); } FEM::InitData() { println("Initialize Data ..."); SetSelSample(-1, 1, -1, 1); // full sample GetGroupNames(Y_VAR,&m_asY); m_mY = GetGroup(Y_VAR); m_cY = sizec(m_mY); //println("sizer(m_mY) = ",sizer(m_mY)); if (sumc(m_vM[3:5])!=0) { m_vS = strfind(m_asY,m_asSelect)'; m_vS = constant(-1,m_cY-sumc(m_vM[3:5]),1)|m_vS; } m_vThres = new matrix[m_cY][1]; for (decl m = 0; m) asRestrictions[eq] = m_asRestrictions[r][1:]; } decl asnames = GetParNames(); decl mE = new matrix[m_cNT][m_cY]; // mean decl InitParX = 0,par_m,samp_m,y_m,x_m,err_m,posx=0,posk; for (decl m = 0; m1) { aThres[m][n][0] = aThres[m][n-1][0]+exp(aThres[m][n][0]); } } pos += m_vThres[m]; } } // Covariance mCov = unvech(vP[pos:]); //println("unvech = ",mCov); for (decl m=0; m1) { aThres[m][n][0] = aThres[m][n-1][0]+exp(aThres[m][n][0]); } } pos += m_vThres[m]; } } // println("asThres = ",aThres); // Covariance /* mCovA = unvech(vP[pos:pos + (m_cY^2-m_cY)/2 + m_cY - 1]); //println("unvech = ",mCov); for (decl m=0; m= MAX_CONV && m_iResult < MAX_MAXIT) m_iModelStatus = MS_ESTIMATED; else m_iModelStatus = MS_EST_FAILED; if (m_fPrint) { Output(); if (isarray(estout)) OutputMax(estout[1], m_iResult, vpstart, estout[2]); } } return m_iModelStatus == MS_ESTIMATED; } FEM::DoEstimation(vStart) { MaxControl(-1,1); println("Model :",GetModel()); println("\nStarting Optimization ..."); println("Initial Values used "); print("%c",GetFreeParNames(),GetFreePar()'); decl time0 = timer(); if (m_iModel==M_INIT) { m_iResult = MaxBFGS(fm_init, &vStart, &m_dLogLik, 0, TRUE); } if (m_iModel==M_TRANS) { m_iResult = MaxBFGS(fm_trans, &vStart, &m_dLogLik, 0, TRUE); } SetResult(m_iResult); if (m_iResult!=9) { println("Calculating Standard Errors ..."); println("Time taken for estimation :",timespan(timer(),time0)); // m_iResult has return code, vStart will have new params m_dLogLik *= m_cN; // change to unscaled log-lik m_iT1est = 0; m_iT2est = m_cN-1; } return {vStart, "BFGS", FALSE}; // three return values } FEM::Covar() { decl mH,mHinv,mG; if (m_iModel==M_INIT) { if (m_iStdErr==HESSIAN) { Num2Derivative(fm_init,GetFreePar(),&mH); mHinv = -invert(mH)./m_cN; if (mHinv==0){ mHinv = constant(.NaN,GetFreeParCount(),GetFreeParCount()); } m_mCovar = mHinv; } if (m_iStdErr==OGP) { mG = fnGradient(fm_initi,GetFreePar(),0); m_mCovar = invert(mG'*mG); if (m_mCovar==0) { m_mCovar = constant(.NaN,GetFreeParCount(),GetFreeParCount()); } } } if (m_iModel==M_TRANS) { if (m_iStdErr==HESSIAN) { Num2Derivative(fm_trans,GetFreePar(),&mH); mHinv = -invert(mH)./m_cN; if (mHinv==0){ mHinv = constant(.NaN,GetFreeParCount(),GetFreeParCount()); } m_mCovar = mHinv; } if (m_iStdErr==OGP) { mG = fnGradient(fm_transi,GetFreePar(),0); m_mCovar = invertsym(mG'*mG); } } return TRUE; } FEM::GetcT() { return m_cN; } FEM::Output() { if (!OutputHeader(GetPackageName())) // returns FALSE if no estimation return; OutputPar(); OutputLogLik(); SavePar(GetFreePar()); } FEM::OutputHeader(const sTitle) { println("\n---- ", sTitle, " ----"); println("Model: ",GetModel()); print("\n"); return TRUE; } FEM::OutputPar() { decl i, tval, abstval, tprob; decl aspar,aspartypes; aspar = GetParNames(); aspartypes = m_asParTypes; decl cpartypes = isarray(aspartypes) ? sizeof(aspartypes) : 0; decl vstderr = GetStdErr(), vrobstderr = GetStdErrRobust(), bcovarrobust = FALSE; decl ct = GetcT(); decl mpar, vp = GetPar(); decl cp = rows(vp); decl cdfloss = GetcDfLoss(); mpar = vp ~ vstderr ~ vp ./ vstderr; if (rows(vrobstderr) > 1) { mpar ~= vrobstderr ~ vp ./ vrobstderr; bcovarrobust = TRUE; } print("%32s", "Coefficient", "%11s", "Std.Error"); if (bcovarrobust) print("%11s", "robust-SE"); println("%9s", "t-value", "%8s", "t-prob"); for (i = 0; i < cp; ++i) { // if (!m_vIsFreePar[i] && mpar[i][0] == 0) //continue; tval = mpar[i][2]; if (i < cpartypes) print("%-13s", aspar[i], " ", "%-2s", aspartypes[i], "%#13.6g", mpar[i][0]); else print("%-16s", aspar[i], "%#13.6g", mpar[i][0]); if (!m_vIsFreePar[i]) println(" (fixed)"); else if (mpar[i][1] > 0) { print("%#11.4g", mpar[i][1]); if (bcovarrobust) { tval = mpar[i][4]; print("%#11.4g", mpar[i][3]); } abstval = fabs(tval); tprob = 2 * tailt(abstval, ct - cdfloss); println(abstval <= 1e-4 ? "%9.2f" : abstval >= 1e3 ? "%#9.4g" : "%#9.3g", tval, "%8.3f", tprob); } else print("\n"); } } FEM::OutputLogLik() { decl ct = GetcT(); decl cdfloss = GetcDfLoss(); print("%r",{"equation "},"%c",m_asY,range(0,m_cY-1,1)); println("\nlog-likelihood", "%15.9g", m_dLogLik); println("no. of observations", "%10d", ct, " no. of parameters ", "%10d", cdfloss); println("no. of draws ", "%10d", int(m_cR), " no. of dimensions ", "%10d", int(m_cY)); } FEM::OutputMax(const sMethod, const iResult, const vPstart, const bNumerical) { /* if (iResult >= 0) { decl deps1, deps2; [deps1, deps2] = GetMaxControlEps(); println(sMethod, " using ", bNumerical ? "analytical" : "numerical", " derivatives (eps1=", deps1, "; eps2=", deps2, "):\n", MaxConvergenceMsg(iResult)); } if (sizerc(vPstart)) print("Used starting values:", vec(vPstart)', "\n"); */ } /** This function saves the results to a useful set of excel spreadsheets. - Means_Init are the betas for the regressions - Thresholds_Init are the cut points for any ordered outcomes - CovarianceU_Init is the covariance matrix \bug NaN's are not output consistently. Sometimes they show up as huge positives, sometimes \#NUM, etc. Might be an Excel problem, but the output here should be made consistent. \todo save these crucial parameters in a fashion that allows Stata to read them in automatically. Converting the means and covariance spreadsheets to CSV is close, but still requires a manual step. Even worse are the cut points, which currently need to be typed in by hand directly in to new51_simulate.do, making it impossible to run multiple scenarios easily. */ FEM::SavePar(const vFreePar) { if (m_iModel==M_INIT) { println("Saving Parameter Estimates ..."); decl mPx,aThres,mCov; aThres = new array[m_cY]; [mPx,aThres,mCov] = fMapFreetoPar(GetFreePar()); decl mThres; mThres = zeros(maxc(m_vThres),m_cY); for (decl m = 0; m, m_asY, "row"); ctMeans.AddData(<1,0>, m_asZ, "column"); ctMeans.AddData(<1,1>, mPx); ctMeans.Write("param/"+m_iName+"_Means_Init.csv"); decl ctThresh = new CellTable(); ctMeans.AddData(<0,0>, m_asY, "row"); ctMeans.AddData(<1,0>, selectifc(mThres,( m_vType.==ORDER || m_vType.==CENSORORDER)')); ctMeans.Write("param/"+m_iName+"_Thresholds_Init.csv"); decl ctCovar = new CellTable(); ctCovar.AddData(<0,1>, m_asY, "row"); ctCovar.AddData(<1,0>, m_asY, "column"); ctCovar.AddData(<1,1>, mCov); ctCovar.Write("param/"+m_iName+"_CovarianceU_Init.csv"); } // end Initial Condition Model if (m_iModel==M_TRANS) { println("Saving Parameter Estimates ..."); savemat("CovFreePar_Trans.in7",m_mCovar); savemat("FreePar_Trans.xls",GetFreePar()); savemat("Par_Trans.xls",GetPar()); } // end Initial Condition Model }