void ba81NormalQuad::layer::setStructure(Eigen::ArrayBase<T1> ¶m, Eigen::MatrixBase<T2> &gmean, Eigen::MatrixBase<T3> &gcov) { abilitiesMap.clear(); std::string str = string_snprintf("layer:"); for (int ax=0; ax < gmean.rows(); ++ax) { if (!abilitiesMask[ax]) continue; abilitiesMap.push_back(ax); str += " "; str += quad->ig.factorNames[ax]; } str += ":"; itemsMap.clear(); glItemsMap.resize(param.cols(), -1); for (int ix=0, lx=0; ix < param.cols(); ++ix) { if (!itemsMask[ix]) continue; itemsMap.push_back(ix); glItemsMap[ix] = lx++; str += string_snprintf(" %d", ix); } str += "\n"; //mxLogBig(str); dataColumns.clear(); dataColumns.reserve(numItems()); totalOutcomes = 0; for (int ix=0; ix < numItems(); ++ix) { int outcomes = quad->ig.itemOutcomes[ itemsMap[ix] ]; itemOutcomes.push_back(outcomes); cumItemOutcomes.push_back(totalOutcomes); totalOutcomes += outcomes; dataColumns.push_back(quad->ig.dataColumns[ itemsMap[ix] ]); } Eigen::VectorXd mean; Eigen::MatrixXd cov; globalToLocalDist(gmean, gcov, mean, cov); if (mean.size() == 0) { numSpecific = 0; primaryDims = 0; maxDims = 1; totalQuadPoints = 1; totalPrimaryPoints = 1; weightTableSize = 1; return; } numSpecific = 0; if (quad->ig.twotier) detectTwoTier(param, mean, cov); if (numSpecific) quad->hasBifactorStructure = true; primaryDims = cov.cols() - numSpecific; maxDims = primaryDims + (numSpecific? 1 : 0); totalQuadPoints = 1; for (int dx=0; dx < maxDims; dx++) { totalQuadPoints *= quad->gridSize; } totalPrimaryPoints = totalQuadPoints; weightTableSize = totalQuadPoints; if (numSpecific) { totalPrimaryPoints /= quad->gridSize; weightTableSize *= numSpecific; } }
void ifaGroup::import(SEXP Rlist) { SEXP argNames; Rf_protect(argNames = Rf_getAttrib(Rlist, R_NamesSymbol)); if (Rf_length(Rlist) != Rf_length(argNames)) { Rf_error("All list elements must be named"); } std::vector<const char *> dataColNames; paramRows = -1; int pmatCols=-1; int mips = 1; int dataRows = 0; SEXP Rmean=0, Rcov=0; for (int ax=0; ax < Rf_length(Rlist); ++ax) { const char *key = R_CHAR(STRING_ELT(argNames, ax)); SEXP slotValue = VECTOR_ELT(Rlist, ax); if (strEQ(key, "spec")) { importSpec(slotValue); } else if (strEQ(key, "param")) { if (!Rf_isReal(slotValue)) Rf_error("'param' must be a numeric matrix of item parameters"); param = REAL(slotValue); getMatrixDims(slotValue, ¶mRows, &pmatCols); SEXP dimnames; Rf_protect(dimnames = Rf_getAttrib(slotValue, R_DimNamesSymbol)); if (!Rf_isNull(dimnames) && Rf_length(dimnames) == 2) { SEXP names; Rf_protect(names = VECTOR_ELT(dimnames, 0)); int nlen = Rf_length(names); factorNames.resize(nlen); for (int nx=0; nx < nlen; ++nx) { factorNames[nx] = CHAR(STRING_ELT(names, nx)); } Rf_protect(names = VECTOR_ELT(dimnames, 1)); nlen = Rf_length(names); itemNames.resize(nlen); for (int nx=0; nx < nlen; ++nx) { itemNames[nx] = CHAR(STRING_ELT(names, nx)); } } } else if (strEQ(key, "mean")) { Rmean = slotValue; if (!Rf_isReal(slotValue)) Rf_error("'mean' must be a numeric vector or matrix"); mean = REAL(slotValue); } else if (strEQ(key, "cov")) { Rcov = slotValue; if (!Rf_isReal(slotValue)) Rf_error("'cov' must be a numeric matrix"); cov = REAL(slotValue); } else if (strEQ(key, "data")) { Rdata = slotValue; dataRows = Rf_length(VECTOR_ELT(Rdata, 0)); SEXP names; Rf_protect(names = Rf_getAttrib(Rdata, R_NamesSymbol)); int nlen = Rf_length(names); dataColNames.reserve(nlen); for (int nx=0; nx < nlen; ++nx) { dataColNames.push_back(CHAR(STRING_ELT(names, nx))); } Rf_protect(dataRowNames = Rf_getAttrib(Rdata, R_RowNamesSymbol)); } else if (strEQ(key, "weightColumn")) { if (Rf_length(slotValue) != 1) { Rf_error("You can only have one weightColumn"); } weightColumnName = CHAR(STRING_ELT(slotValue, 0)); } else if (strEQ(key, "qwidth")) { qwidth = Rf_asReal(slotValue); } else if (strEQ(key, "qpoints")) { qpoints = Rf_asInteger(slotValue); } else if (strEQ(key, "minItemsPerScore")) { mips = Rf_asInteger(slotValue); } else { // ignore } } learnMaxAbilities(); if (maxAbilities < (int) factorNames.size()) factorNames.resize(maxAbilities); if (!factorNames.size()) { factorNames.reserve(maxAbilities); const int SMALLBUF = 10; char buf[SMALLBUF]; for (int sx=0; sx < maxAbilities; ++sx) { snprintf(buf, SMALLBUF, "s%d", sx+1); factorNames.push_back(CHAR(Rf_mkChar(buf))); } } if (Rmean) { if (Rf_isMatrix(Rmean)) { int nrow, ncol; getMatrixDims(Rmean, &nrow, &ncol); if (!(nrow * ncol == maxAbilities && (nrow==1 || ncol==1))) { Rf_error("mean must be a column or row matrix of length %d", maxAbilities); } } else { if (Rf_length(Rmean) != maxAbilities) { Rf_error("mean must be a vector of length %d", maxAbilities); } } verifyFactorNames(Rmean, "mean"); } if (Rcov) { if (Rf_isMatrix(Rcov)) { int nrow, ncol; getMatrixDims(Rcov, &nrow, &ncol); if (nrow != maxAbilities || ncol != maxAbilities) { Rf_error("cov must be %dx%d matrix", maxAbilities, maxAbilities); } } else { if (Rf_length(Rcov) != 1) { Rf_error("cov must be %dx%d matrix", maxAbilities, maxAbilities); } } verifyFactorNames(Rcov, "cov"); } setLatentDistribution(maxAbilities, mean, cov); setMinItemsPerScore(mips); if (numItems() != pmatCols) { Rf_error("item matrix implies %d items but spec is length %d", pmatCols, numItems()); } if (Rdata) { if (itemNames.size() == 0) Rf_error("Item matrix must have colnames"); for (int ix=0; ix < numItems(); ++ix) { bool found=false; for (int dc=0; dc < int(dataColNames.size()); ++dc) { if (strEQ(itemNames[ix], dataColNames[dc])) { SEXP col = VECTOR_ELT(Rdata, dc); if (!Rf_isFactor(col)) { if (TYPEOF(col) == INTSXP) { Rf_error("Column '%s' is an integer but " "not an ordered factor", dataColNames[dc]); } else { Rf_error("Column '%s' is of type %s; expecting an " "ordered factor (integer)", dataColNames[dc], Rf_type2char(TYPEOF(col))); } } dataColumns.push_back(INTEGER(col)); found=true; break; } } if (!found) { Rf_error("Cannot find item '%s' in data", itemNames[ix]); } } if (weightColumnName) { for (int dc=0; dc < int(dataColNames.size()); ++dc) { if (strEQ(weightColumnName, dataColNames[dc])) { SEXP col = VECTOR_ELT(Rdata, dc); if (TYPEOF(col) != REALSXP) { Rf_error("Column '%s' is of type %s; expecting type numeric (double)", dataColNames[dc], Rf_type2char(TYPEOF(col))); } rowWeight = REAL(col); break; } } if (!rowWeight) { Rf_error("Cannot find weight column '%s'", weightColumnName); } } rowMap.reserve(dataRows); for (int rx=0; rx < dataRows; ++rx) rowMap.push_back(rx); } detectTwoTier(); sanityCheck(); if (paramRows < impliedParamRows) { Rf_error("At least %d rows are required in the item parameter matrix, only %d found", impliedParamRows, paramRows); } Eigen::Map<Eigen::MatrixXd> fullCov(cov, maxAbilities, maxAbilities); int dense = maxAbilities - numSpecific; Eigen::MatrixXd priCov = fullCov.block(0, 0, dense, dense); Eigen::VectorXd sVar = fullCov.diagonal().tail(numSpecific); quad.setup(qwidth, qpoints, mean, priCov, sVar); }