void CovarianceModel::addAppearance(cv::Mat & img, const cv::Rect &detBox)
{
  cv::Mat newCovMat = cv::Mat::zeros(5,5, CV_64FC1);

  cv::Mat target = (detBox == cv::Rect()) ? img : img(detBox);
  cv::cvtColor(target, target, CV_RGB2GRAY);

  const int totalPoints = target.rows * target.cols;

  _Ix.create(target.rows, target.cols, CV_64FC1);
  _Iy.create(target.rows, target.cols, CV_64FC1);
  _Ixx.create(target.rows, target.cols, CV_64FC1);
  _Iyy.create(target.rows, target.cols, CV_64FC1);
  _Ixy.create(target.rows, target.cols, CV_64FC1);

  cv::filter2D(target, _Ix, CV_64FC1, _kernelX);
  cv::filter2D(target, _Iy, CV_64FC1, _kernelY);
  cv::filter2D(target, _Ixx, CV_64FC1, _kernelXX);
  cv::filter2D(target, _Iyy, CV_64FC1, _kernelYY);
  cv::Sobel(target, _Ixy, CV_64FC1, 1, 1);

  cv::Mat meanVec(5, 1, CV_64FC1);
  meanVec.at<double>(0,0) = cv::mean(_Ix)(0); // cv::Scalar s; s(0) will give the first element in the scalar
  meanVec.at<double>(1,0) = cv::mean(_Iy)(0);
  meanVec.at<double>(2,0) = cv::mean(_Ixx)(0);
  meanVec.at<double>(3,0) = cv::mean(_Iyy)(0);
  meanVec.at<double>(4,0) = cv::mean(_Ixy)(0);

  cv::Mat pix(5, 1, CV_64FC1);

  for(int i=0; i<target.rows; ++i)
  {
    for(int j=0; j<target.cols; ++j)
    {
      pix.at<double>(0,0) = _Ix.at<double>(i,j);
      pix.at<double>(1,0) = _Iy.at<double>(i,j);
      pix.at<double>(2,0) = _Ixx.at<double>(i,j);
      pix.at<double>(3,0) = _Iyy.at<double>(i,j);
      pix.at<double>(4,0) = _Ixy.at<double>(i,j);

      const cv::Mat pixMinMeanVec = pix-meanVec;
      const cv::Mat currCovMat = (pixMinMeanVec * pixMinMeanVec.t());

      newCovMat += currCovMat;
    }
  }
  newCovMat /= (totalPoints-1);

  _covMatrices.push_back(newCovMat);

  if(_covMatrices.size() > 2)
    _updateGaussian();
}
// covariance matrix
// WARNING: This is NOT the unbiased covariance in which
// you divide by (n - 1)!  In this case we divide by n.
//
// This is essentially:  (1/maxr) * m.Tdot(m) - meanT . mean
// and so is twice as slow as it needs to be.
// WARNING: allocates new matrix for answer
Matrix &Matrix::cov()
{
    assertDefined("cov");

    // OK, so this does twice the work it should...  zzz  but it was easy :-(
    Matrix mean;
    Matrix *out;

    out = &Tdot(*this);  // Tdot with yourself
    mean = meanVec();
    out->scalarMult(1.0/maxr);
    out->sub(mean.Tdot(mean));

    out->defined = true;

    return *out;
}
Esempio n. 3
0
void ifaGroup::import(SEXP Rlist)
{
	SEXP argNames;
	Rf_protect(argNames = Rf_getAttrib(Rlist, R_NamesSymbol));
	if (Rf_length(Rlist) != Rf_length(argNames)) {
		mxThrow("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)) mxThrow("'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)) mxThrow("'mean' must be a numeric vector or matrix");
			mean = REAL(slotValue);
		} else if (strEQ(key, "cov")) {
			Rcov = slotValue;
			if (!Rf_isReal(slotValue)) mxThrow("'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) {
				mxThrow("You can only have one %s", key);
			}
			weightColumnName = CHAR(STRING_ELT(slotValue, 0));
		} else if (strEQ(key, "freqColumn")) {
			if (Rf_length(slotValue) != 1) {
				mxThrow("You can only have one %s", key);
			}
			freqColumnName = 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 (itemDims < (int) factorNames.size())
		factorNames.resize(itemDims);

	if (int(factorNames.size()) < itemDims) {
		factorNames.reserve(itemDims);
		const int SMALLBUF = 24;
		char buf[SMALLBUF];
		while (int(factorNames.size()) < itemDims) {
			snprintf(buf, SMALLBUF, "s%d", int(factorNames.size()) + 1);
			factorNames.push_back(CHAR(Rf_mkChar(buf)));
		}
	}

	if (Rmean) {
		if (Rf_isMatrix(Rmean)) {
			int nrow, ncol;
			getMatrixDims(Rmean, &nrow, &ncol);
			if (!(nrow * ncol == itemDims && (nrow==1 || ncol==1))) {
				mxThrow("mean must be a column or row matrix of length %d", itemDims);
			}
		} else {
			if (Rf_length(Rmean) != itemDims) {
				mxThrow("mean must be a vector of length %d", itemDims);
			}
		}

		verifyFactorNames(Rmean, "mean");
	}

	if (Rcov) {
		if (Rf_isMatrix(Rcov)) {
			int nrow, ncol;
			getMatrixDims(Rcov, &nrow, &ncol);
			if (nrow != itemDims || ncol != itemDims) {
				mxThrow("cov must be %dx%d matrix", itemDims, itemDims);
			}
		} else {
			if (Rf_length(Rcov) != 1) {
				mxThrow("cov must be %dx%d matrix", itemDims, itemDims);
			}
		}

		verifyFactorNames(Rcov, "cov");
	}

	setLatentDistribution(mean, cov);

	setMinItemsPerScore(mips);

	if (numItems() != pmatCols) {
		mxThrow("item matrix implies %d items but spec is length %d",
			 pmatCols, numItems());
	}

	if (Rdata) {
		if (itemNames.size() == 0) mxThrow("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) {
							mxThrow("Column '%s' is an integer but "
								 "not an ordered factor",
								 dataColNames[dc]);
						} else {
							mxThrow("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) {
				mxThrow("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) {
						mxThrow("Column '%s' is of type %s; expecting type numeric (double)",
							 dataColNames[dc], Rf_type2char(TYPEOF(col)));
					}
					rowWeight = REAL(col);
					break;
				}
			}
			if (!rowWeight) {
				mxThrow("Cannot find weight column '%s'", weightColumnName);
			}
		}
		if (freqColumnName) {
			for (int dc=0; dc < int(dataColNames.size()); ++dc) {
				if (strEQ(freqColumnName, dataColNames[dc])) {
					SEXP col = VECTOR_ELT(Rdata, dc);
					if (TYPEOF(col) != INTSXP) {
						mxThrow("Column '%s' is of type %s; expecting type integer",
							 dataColNames[dc], Rf_type2char(TYPEOF(col)));
					}
					rowFreq = INTEGER(col);
					break;
				}
			}
			if (!rowFreq) {
				mxThrow("Cannot find frequency column '%s'", freqColumnName);
			}
		}
		rowMap.reserve(dataRows);
		for (int rx=0; rx < dataRows; ++rx) rowMap.push_back(rx);
	}

	Eigen::Map< Eigen::ArrayXXd > Eparam(param, paramRows, numItems());
	Eigen::Map< Eigen::VectorXd > meanVec(mean, itemDims);
	Eigen::Map< Eigen::MatrixXd > covMat(cov, itemDims, itemDims);

	quad.setStructure(qwidth, qpoints, Eparam, meanVec, covMat);

	if (paramRows < impliedParamRows) {
		mxThrow("At least %d rows are required in the item parameter matrix, only %d found",
			 impliedParamRows, paramRows);
	}
	
	quad.refresh(meanVec, covMat);
}
Esempio n. 4
0
/*******************************************************************************
* data      - p x n column matrix of data points
* p         - dimension of data points
* n         - number of data points
* radius    - radius of search windo
* rate      - gradient descent proportionality factor
* maxIter   - max allowed number of iterations
* blur      - specifies algorithm mode
* labels    - labels for each cluster
* means     - output (final clusters)
*******************************************************************************/
void meanShift( double data[], int p, int n, double radius, double rate,
        int maxIter, bool blur, double labels[], double *means ) {
  double radius2;    /* radius^2 */
  int iter;          /* number of iterations */
  double *mean;      /* mean vector */
  int i, j, o, m;    /* looping and temporary variables */
  int delta = 1;     /* indicator if change occurred between iterations */
  int *deltas;       /* indicator if change occurred between iterations per point */
  double *meansCur;  /* calculated means for current iter */
  double *meansNxt;  /* calculated means for next iter */
  double *data1;     /* If blur data1 points to meansCur else it points to data */
  int *consolidated; /* Needed in the assignment of cluster labels */
  int nLabels = 1;   /* Needed in the assignment of cluster labels */
  
  /* initialization */
  meansCur = (double*) malloc( sizeof(double)*p*n );
  meansNxt = (double*) malloc( sizeof(double)*p*n );
  mean = (double*) malloc( sizeof(double)*p );
  consolidated = (int*) malloc( sizeof(int)*n );
  deltas = (int*) malloc( sizeof(int)*n );
  for(i=0; i<n; i++) deltas[i] = 1;
  radius2 = radius * radius;
  meansCur = (double*) memcpy(meansCur, data, p*n*sizeof(double) );
  if( blur ) data1=meansCur; else data1=data;
  
  /* main loop */
  mexPrintf("Progress: 0.000000"); mexEvalString("drawnow;");
  for(iter=0; iter<maxIter; iter++) {
    delta = 0;
    for( i=0; i<n; i++ ) {
      if( deltas[i] ) {
        /* shift meansNxt in direction of mean (if m>0) */
        o=i*p; m=meanVec( meansCur+o, data1, p, n, radius2, mean );
        if( m ) {
          for( j=0; j<p; j++ ) meansNxt[o+j] = (1-rate)*meansCur[o+j] + rate*mean[j];
          if( dist(meansNxt+o, meansCur+o, p)>0.001) delta=1; else deltas[i]=0;
        } else {
          for( j=0; j<p; j++ ) meansNxt[o+j] = meansCur[o+j]; deltas[i]=0;
        }
      }
    }
    mexPrintf( "\b\b\b\b\b\b\b\b%f", (float)(iter+1)/maxIter ); mexEvalString("drawnow;");
    memcpy( meansCur, meansNxt, p*n*sizeof(double) ); if(!delta) break;
  }
  mexPrintf( "\n" );
  
  /* Consolidate: assign all points that are within radius2 to same cluster. */
  for( i=0; i<n; i++ ) { consolidated[i]=0; labels[i]=0; }
  for( i=0; i<n; i++ ) if( !consolidated[i]) {
    for( j=0; j<n; j++ ) if( !consolidated[j]) {
      if( dist(meansCur+i*p, meansCur+j*p, p) < radius2) {
        labels[j]=nLabels; consolidated[j]=1;
      }
    }
    nLabels++;
  }
  nLabels--; memcpy( means, meansCur, p*n*sizeof(double) );
  
  /* free memory */
  free(meansNxt); free(meansCur); free(mean); free(consolidated); free(deltas);
}
Esempio n. 5
0
void compute(const QUESO::FullEnvironment& env) {

  struct timeval timevalNow;
  gettimeofday(&timevalNow, NULL);
  std::cout << std::endl << "Beginning run of 'Hysteretic' example at "
            << ctime(&timevalNow.tv_sec);

  //------------------------------------------------------
  // Step 1 of 5: Instantiate the parameter space
  //------------------------------------------------------
  QUESO::VectorSpace<> paramSpaceA(env, "paramA_", 1, NULL);
  QUESO::VectorSpace<> paramSpaceB(env, "paramB_", 14, NULL);
  QUESO::VectorSpace<> paramSpace (env, "param_", 15, NULL);

  //------------------------------------------------------
  // Step 2 of 5: Instantiate the parameter domain
  //------------------------------------------------------
  QUESO::GslVector paramMinsA(paramSpaceA.zeroVector());
  paramMinsA.cwSet(0);
  QUESO::GslVector paramMaxsA(paramSpaceA.zeroVector());
  paramMaxsA.cwSet(5);
  QUESO::BoxSubset<> paramDomainA("paramA_",paramSpaceA,paramMinsA,paramMaxsA);

  QUESO::GslVector paramMinsB(paramSpaceB.zeroVector());
  paramMinsB.cwSet(-INFINITY);
  QUESO::GslVector paramMaxsB(paramSpaceB.zeroVector());
  paramMaxsB.cwSet( INFINITY);
  QUESO::BoxSubset<> paramDomainB("paramB_",paramSpaceB,paramMinsB,paramMaxsB);

  QUESO::ConcatenationSubset<> paramDomain("",paramSpace,paramDomainA,paramDomainB);

  //------------------------------------------------------
  // Step 3 of 5: Instantiate the likelihood function object
  //------------------------------------------------------
  std::cout << "\tInstantiating the Likelihood; calling internally the hysteretic model"
	    << std::endl;

  Likelihood<> likelihood("like_", paramDomain);

  likelihood.floor.resize(4,NULL);
  unsigned int numTimeSteps = 401;
  for (unsigned int i = 0; i < 4; ++i) {
    likelihood.floor[i] = new std::vector<double>(numTimeSteps,0.);
  }
  likelihood.accel.resize(numTimeSteps,0.);
  FILE *inp;
  inp = fopen("an.txt","r");
  unsigned int numObservations = 0;
  double tmpA;
  while (fscanf(inp,"%lf",&tmpA) != EOF) {
    likelihood.accel[numObservations] = tmpA;
    numObservations++;
  }

  numObservations=1;
  FILE *inp1_1;
  inp1_1=fopen("measured_data1_1.txt","r");
  while (fscanf(inp1_1,"%lf",&tmpA) != EOF) {
    (*likelihood.floor[0])[numObservations]=tmpA;
     numObservations++;
  }

  numObservations=0;
  FILE *inp1_2;
  inp1_2=fopen("measured_data1_2.txt","r");
  while (fscanf(inp1_2,"%lf",&tmpA) != EOF) {
    (*likelihood.floor[1])[numObservations]=tmpA;
    numObservations++;
  }

  numObservations=0;
  FILE *inp1_3;
  inp1_3=fopen("measured_data1_3.txt","r");
  while (fscanf(inp1_3,"%lf",&tmpA) != EOF) {
    (*likelihood.floor[2])[numObservations]=tmpA;
    numObservations++;
  }

  numObservations=0;
  FILE *inp1_4;
  inp1_4=fopen("measured_data1_4.txt","r");
  while (fscanf(inp1_4,"%lf",&tmpA) != EOF) {
    (*likelihood.floor[3])[numObservations]=tmpA;
    numObservations++;
  }


  //------------------------------------------------------
  // Step 4 of 5: Instantiate the inverse problem
  //------------------------------------------------------
  std::cout << "\tInstantiating the SIP" << std::endl;

  QUESO::UniformVectorRV<> priorRvA("priorA_", paramDomainA);

  QUESO::GslVector meanVec(paramSpaceB.zeroVector());
  QUESO::GslVector diagVec(paramSpaceB.zeroVector());

  diagVec.cwSet(0.6*0.6);

  QUESO::GslMatrix covMatrix(diagVec);

  QUESO::GaussianVectorRV<> priorRvB("priorB_", paramDomainB,meanVec,covMatrix);

  QUESO::ConcatenatedVectorRV<> priorRv("prior_", priorRvA, priorRvB, paramDomain);

  QUESO::GenericVectorRV<> postRv("post_", paramSpace);

  QUESO::StatisticalInverseProblem<> ip("", NULL, priorRv, likelihood, postRv);

  //------------------------------------------------------
  // Step 5 of 5: Solve the inverse problem
  //------------------------------------------------------
  std::cout << "\tSolving the SIP with Multilevel method" << std::endl;

  ip.solveWithBayesMLSampling();

  gettimeofday(&timevalNow, NULL);
  std::cout << "Ending run of 'Hysteretic' example at "
              << ctime(&timevalNow.tv_sec) << std::endl;
  return;
}
Esempio n. 6
0
void omxInitExpectationBA81(omxExpectation* oo) {
	omxState* currentState = oo->currentState;	
	SEXP rObj = oo->rObj;
	SEXP tmp;
	
	if(OMX_DEBUG) {
		mxLog("Initializing %s.", oo->name);
	}
	if (!Glibrpf_model) {
#if USE_EXTERNAL_LIBRPF
		get_librpf_t get_librpf = (get_librpf_t) R_GetCCallable("rpf", "get_librpf_model_GPL");
		(*get_librpf)(LIBIFA_RPF_API_VERSION, &Glibrpf_numModels, &Glibrpf_model);
#else
		// if linking against included source code
		Glibrpf_numModels = librpf_numModels;
		Glibrpf_model = librpf_model;
#endif
	}
	
	BA81Expect *state = new BA81Expect;

	// These two constants should be as identical as possible
	state->name = oo->name;
	if (0) {
		state->LogLargestDouble = 0.0;
		state->LargestDouble = 1.0;
	} else {
		state->LogLargestDouble = log(std::numeric_limits<double>::max()) - 1;
		state->LargestDouble = exp(state->LogLargestDouble);
		ba81NormalQuad &quad = state->getQuad();
		quad.setOne(state->LargestDouble);
	}

	state->expectedUsed = false;

	state->estLatentMean = NULL;
	state->estLatentCov = NULL;
	state->type = EXPECTATION_OBSERVED;
	state->itemParam = NULL;
	state->EitemParam = NULL;
	state->itemParamVersion = 0;
	state->latentParamVersion = 0;
	oo->argStruct = (void*) state;

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("data")));
	state->data = omxDataLookupFromState(tmp, currentState);
	}

	if (strcmp(omxDataType(state->data), "raw") != 0) {
		omxRaiseErrorf("%s unable to handle data type %s", oo->name, omxDataType(state->data));
		return;
	}

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("verbose")));
	state->verbose = Rf_asInteger(tmp);
	}

	int targetQpoints;
	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("qpoints")));
		targetQpoints = Rf_asInteger(tmp);
	}

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("qwidth")));
	state->grp.setGridFineness(Rf_asReal(tmp), targetQpoints);
	}

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("ItemSpec")));
	state->grp.importSpec(tmp);
	if (state->verbose >= 2) mxLog("%s: found %d item specs", oo->name, state->numItems());
	}

	state->_latentMeanOut = omxNewMatrixFromSlot(rObj, currentState, "mean");
	state->_latentCovOut  = omxNewMatrixFromSlot(rObj, currentState, "cov");

	state->itemParam = omxNewMatrixFromSlot(rObj, currentState, "item");
	state->grp.param = state->itemParam->data; // algebra not allowed yet TODO

	const int numItems = state->itemParam->cols;
	if (state->numItems() != numItems) {
		omxRaiseErrorf("ItemSpec length %d must match the number of item columns (%d)",
			       state->numItems(), numItems);
		return;
	}
	if (state->itemParam->rows != state->grp.impliedParamRows) {
		omxRaiseErrorf("item matrix must have %d rows", state->grp.impliedParamRows);
		return;
	}
	state->grp.paramRows = state->itemParam->rows;

	// for algebra item param, will need to defer until later?
	state->grp.learnMaxAbilities();

	int maxAbilities = state->grp.itemDims;
	state->grp.setFactorNames(state->itemParam->rownames);

	{
		ProtectedSEXP tmp2(R_do_slot(rObj, Rf_install(".detectIndependence")));
		state->grp.detectIndependence = Rf_asLogical(tmp2);
	}

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("EstepItem")));
	if (!Rf_isNull(tmp)) {
		int rows, cols;
		getMatrixDims(tmp, &rows, &cols);
		if (rows != state->itemParam->rows || cols != state->itemParam->cols) {
			Rf_error("EstepItem must have the same dimensions as the item MxMatrix");
		}
		state->EitemParam = REAL(tmp);
	}
	}

	oo->computeFun = ba81compute;
	oo->setVarGroup = ignoreSetVarGroup;
	oo->destructFun = ba81Destroy;
	oo->populateAttrFun = ba81PopulateAttributes;
	oo->componentFun = getComponent;
	oo->canDuplicate = false;
	
	// TODO: Exactly identical rows do not contribute any information.
	// The sorting algorithm ought to remove them so we get better cache behavior.
	// The following summary stats would be cheaper to calculate too.

	omxData *data = state->data;
	if (data->hasDefinitionVariables()) Rf_error("%s: not implemented yet", oo->name);

	std::vector<int> &rowMap = state->grp.rowMap;

	int weightCol;
	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("weightColumn")));
		weightCol = INTEGER(tmp)[0];
	}

	if (weightCol == NA_INTEGER) {
		// Should rowMap be part of omxData? This is essentially a
		// generic compression step that shouldn't be specific to IFA models.
		state->grp.rowWeight = (double*) R_alloc(data->rows, sizeof(double));
		rowMap.resize(data->rows);
		int numUnique = 0;
		for (int rx=0; rx < data->rows; ) {
			int rw = 1;
			state->grp.rowWeight[numUnique] = rw;
			rowMap[numUnique] = rx;
			rx += rw;
			++numUnique;
		}
		rowMap.resize(numUnique);
		state->weightSum = state->data->rows;
	}
	else {
		if (omxDataColumnIsFactor(data, weightCol)) {
			omxRaiseErrorf("%s: weightColumn %d is a factor", oo->name, 1 + weightCol);
			return;
		}
		state->grp.rowWeight = omxDoubleDataColumn(data, weightCol);
		state->weightSum = 0;
		for (int rx=0; rx < data->rows; ++rx) { state->weightSum += state->grp.rowWeight[rx]; }
		rowMap.resize(data->rows);
		for (size_t rx=0; rx < rowMap.size(); ++rx) {
			rowMap[rx] = rx;
		}
	}
	// complain about non-integral rowWeights (EAP can't work) TODO

	auto colMap = oo->getDataColumns();

	for (int cx = 0; cx < numItems; cx++) {
		int *col = omxIntDataColumnUnsafe(data, colMap[cx]);
		state->grp.dataColumns.push_back(col);
	}

	// sanity check data
	for (int cx = 0; cx < numItems; cx++) {
		if (!omxDataColumnIsFactor(data, colMap[cx])) {
			data->omxPrintData("diagnostic", 3);
			omxRaiseErrorf("%s: column %d is not a factor", oo->name, int(1 + colMap[cx]));
			return;
		}
	}

	// TODO the max outcome should be available from omxData
	for (int rx=0; rx < data->rows; rx++) {
		int cols = 0;
		for (int cx = 0; cx < numItems; cx++) {
			const int *col = state->grp.dataColumns[cx];
			int pick = col[rx];
			if (pick == NA_INTEGER) continue;
			++cols;
			const int no = state->grp.itemOutcomes[cx];
			if (pick > no) {
				Rf_error("Data for item '%s' has at least %d outcomes, not %d",
					 state->itemParam->colnames[cx], pick, no);
			}
		}
		if (cols == 0) {
			Rf_error("Row %d has all NAs", 1+rx);
		}
	}

	if (state->_latentMeanOut && state->_latentMeanOut->rows * state->_latentMeanOut->cols != maxAbilities) {
		Rf_error("The mean matrix '%s' must be a row or column vector of size %d",
			 state->_latentMeanOut->name(), maxAbilities);
	}

	if (state->_latentCovOut && (state->_latentCovOut->rows != maxAbilities ||
				    state->_latentCovOut->cols != maxAbilities)) {
		Rf_error("The cov matrix '%s' must be %dx%d",
			 state->_latentCovOut->name(), maxAbilities, maxAbilities);
	}

	state->grp.setLatentDistribution(state->_latentMeanOut? state->_latentMeanOut->data : NULL,
					 state->_latentCovOut? state->_latentCovOut->data : NULL);

	{
		EigenArrayAdaptor Eparam(state->itemParam);
		Eigen::Map< Eigen::VectorXd > meanVec(state->grp.mean, maxAbilities);
		Eigen::Map< Eigen::MatrixXd > covMat(state->grp.cov, maxAbilities, maxAbilities);
		state->grp.quad.setStructure(state->grp.qwidth, state->grp.qpoints,
					     Eparam, meanVec, covMat);
	}

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("minItemsPerScore")));
	state->grp.setMinItemsPerScore(Rf_asInteger(tmp));
	}

	state->grp.buildRowSkip();

	if (isErrorRaised()) return;

	{ScopedProtect p1(tmp, R_do_slot(rObj, Rf_install("debugInternal")));
	state->debugInternal = Rf_asLogical(tmp);
	}

	state->ElatentVersion = 0;
	if (state->_latentMeanOut) {
		state->estLatentMean = omxInitMatrix(maxAbilities, 1, TRUE, currentState);
		omxCopyMatrix(state->estLatentMean, state->_latentMeanOut); // rename matrices TODO
	}
	if (state->_latentCovOut) {
		state->estLatentCov = omxInitMatrix(maxAbilities, maxAbilities, TRUE, currentState);
		omxCopyMatrix(state->estLatentCov, state->_latentCovOut);
	}
}