Ejemplo n.º 1
0
void ba81NormalQuad::layer::setStructure(Eigen::ArrayBase<T1> &param,
					 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;
	}
}
Ejemplo n.º 2
0
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, &paramRows, &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);
}