static void ba81ComputeFit(omxFitFunction* oo, int want, FitContext *fc) { BA81FitState *state = (BA81FitState*) oo->argStruct; BA81Expect *estate = (BA81Expect*) oo->expectation->argStruct; if (fc) state->numFreeParam = fc->varGroup->vars.size(); if (want & FF_COMPUTE_INITIAL_FIT) return; if (estate->type == EXPECTATION_AUGMENTED) { buildItemParamMap(oo, fc); if (want & FF_COMPUTE_PARAMFLAVOR) { for (size_t px=0; px < state->numFreeParam; ++px) { if (state->paramFlavor[px] == NULL) continue; fc->flavor[px] = state->paramFlavor[px]; } return; } if (want & FF_COMPUTE_PREOPTIMIZE) { omxExpectationCompute(fc, oo->expectation, NULL); return; } if (want & FF_COMPUTE_INFO) { buildLatentParamMap(oo, fc); if (!state->freeItemParams) { omxRaiseErrorf("%s: no free parameters", oo->name()); return; } ba81SetupQuadrature(oo->expectation); if (fc->infoMethod == INFO_METHOD_HESSIAN) { ba81ComputeEMFit(oo, FF_COMPUTE_HESSIAN, fc); } else { omxRaiseErrorf("Information matrix approximation method %d is not available", fc->infoMethod); return; } return; } double got = ba81ComputeEMFit(oo, want, fc); oo->matrix->data[0] = got; return; } else if (estate->type == EXPECTATION_OBSERVED) { if (want == FF_COMPUTE_STARTING) { buildLatentParamMap(oo, fc); if (state->freeLatents) setLatentStartingValues(oo, fc); return; } if (want & (FF_COMPUTE_INFO | FF_COMPUTE_GRADIENT)) { buildLatentParamMap(oo, fc); // only to check state->freeLatents buildItemParamMap(oo, fc); if (!state->freeItemParams && !state->freeLatents) { omxRaiseErrorf("%s: no free parameters", oo->name()); return; } ba81SetupQuadrature(oo->expectation); if (want & FF_COMPUTE_GRADIENT || (want & FF_COMPUTE_INFO && fc->infoMethod == INFO_METHOD_MEAT)) { gradCov(oo, fc); } else { if (state->freeLatents) { omxRaiseErrorf("Information matrix approximation method %d is not available", fc->infoMethod); return; } if (!state->freeItemParams) { omxRaiseErrorf("%s: no free parameters", oo->name()); return; } sandwich(oo, fc); } } if (want & (FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)) { omxRaiseErrorf("%s: Hessian is not available for observed data", oo->name()); } if (want & FF_COMPUTE_MAXABSCHANGE) { double mac = std::max(omxMaxAbsDiff(state->itemParam, estate->itemParam), omxMaxAbsDiff(state->latentMean, estate->_latentMeanOut)); fc->mac = std::max(mac, omxMaxAbsDiff(state->latentCov, estate->_latentCovOut)); state->copyEstimates(estate); } if (want & FF_COMPUTE_FIT) { omxExpectationCompute(fc, oo->expectation, NULL); Eigen::ArrayXd &patternLik = estate->grp.patternLik; const int numUnique = estate->getNumUnique(); if (state->returnRowLikelihoods) { const double OneOverLargest = estate->grp.quad.getReciprocalOfOne(); omxData *data = estate->data; for (int rx=0; rx < numUnique; rx++) { int dups = omxDataNumIdenticalRows(data, estate->grp.rowMap[rx]); for (int dup=0; dup < dups; dup++) { int dest = omxDataIndex(data, estate->grp.rowMap[rx]+dup); oo->matrix->data[dest] = patternLik[rx] * OneOverLargest; } } } else { double *rowWeight = estate->grp.rowWeight; const double LogLargest = estate->LogLargestDouble; double got = 0; #pragma omp parallel for num_threads(Global->numThreads) reduction(+:got) for (int ux=0; ux < numUnique; ux++) { if (patternLik[ux] == 0) continue; got += rowWeight[ux] * (log(patternLik[ux]) - LogLargest); } double fit = nan("infeasible"); if (estate->grp.excludedPatterns < numUnique) { fit = Global->llScale * got; // add in some badness for excluded patterns fit += fit * estate->grp.excludedPatterns; } if (estate->verbose >= 1) mxLog("%s: observed fit %.4f (%d/%d excluded)", oo->name(), fit, estate->grp.excludedPatterns, numUnique); oo->matrix->data[0] = fit; } } } else { Rf_error("%s: Predict nothing or scores before computing %d", oo->name(), want); } }
static void omxRowFitFunctionSingleIteration(omxFitFunction *localobj, omxFitFunction *sharedobj, int rowbegin, int rowcount, FitContext *fc) { omxRowFitFunction* oro = ((omxRowFitFunction*) localobj->argStruct); omxRowFitFunction* shared_oro = ((omxRowFitFunction*) sharedobj->argStruct); omxMatrix *rowAlgebra, *rowResults; omxMatrix *filteredDataRow, *dataRow, *existenceVector; omxMatrix *dataColumns; omxData *data; int isContiguous, contiguousStart, contiguousLength; int numCols, numRemoves; rowAlgebra = oro->rowAlgebra; rowResults = shared_oro->rowResults; data = oro->data; dataColumns = oro->dataColumns; dataRow = oro->dataRow; filteredDataRow = oro->filteredDataRow; existenceVector = oro->existenceVector; isContiguous = oro->contiguous.isContiguous; contiguousStart = oro->contiguous.start; contiguousLength = oro->contiguous.length; Eigen::VectorXd oldDefs; oldDefs.resize(data->defVars.size()); oldDefs.setConstant(NA_REAL); numCols = dataColumns->cols; int *toRemove = (int*) malloc(sizeof(int) * dataColumns->cols); int *zeros = (int*) calloc(dataColumns->cols, sizeof(int)); for(int row = rowbegin; row < data->rows && (row - rowbegin) < rowcount; row++) { data->handleDefinitionVarList(localobj->matrix->currentState, row, oldDefs.data()); omxStateNextRow(localobj->matrix->currentState); // Advance row // Populate data row numRemoves = 0; if (isContiguous) { omxContiguousDataRow(data, row, contiguousStart, contiguousLength, dataRow); } else { omxDataRow(data, row, dataColumns, dataRow); // Populate data row } markDataRowDependencies(localobj->matrix->currentState, oro); for(int j = 0; j < dataColumns->cols; j++) { double dataValue = omxVectorElement(dataRow, j); if(std::isnan(dataValue)) { numRemoves++; toRemove[j] = 1; omxSetVectorElement(existenceVector, j, 0); } else { toRemove[j] = 0; omxSetVectorElement(existenceVector, j, 1); } } // TODO: Determine if this is the correct response. if(numRemoves == numCols) { char *errstr = (char*) calloc(250, sizeof(char)); sprintf(errstr, "Row %d completely missing. omxRowFitFunction cannot have completely missing rows.", omxDataIndex(data, row)); omxRaiseError(errstr); free(errstr); continue; } omxCopyMatrix(filteredDataRow, dataRow); omxRemoveRowsAndColumns(filteredDataRow, 0, numRemoves, zeros, toRemove); omxRecompute(rowAlgebra, fc); omxCopyMatrixToRow(rowAlgebra, omxDataIndex(data, row), rowResults); } free(toRemove); free(zeros); }