void loglikelihoodCIFun(omxFitFunction *ff, int want, FitContext *fc) { const omxConfidenceInterval *CI = fc->CI; if (want & FF_COMPUTE_PREOPTIMIZE) { fc->targetFit = (fc->lowerBound? CI->lbound : CI->ubound) + fc->fit; //mxLog("Set target fit to %f (MLE %f)", fc->targetFit, fc->fit); return; } if (!(want & FF_COMPUTE_FIT)) { Rf_error("Not implemented yet"); } omxMatrix *fitMat = ff->matrix; // We need to compute the fit here because that's the only way to // check our soft feasibility constraints. If parameters don't // change between here and the constraint evaluation then we // should avoid recomputing the fit again in the constraint. TODO omxFitFunctionCompute(fitMat->fitFunction, FF_COMPUTE_FIT, fc); const double fit = totalLogLikelihood(fitMat); omxRecompute(CI->matrix, fc); double CIElement = omxMatrixElement(CI->matrix, CI->row, CI->col); omxResizeMatrix(fitMat, 1, 1); if (!std::isfinite(fit) || !std::isfinite(CIElement)) { fc->recordIterationError("Confidence interval is in a range that is currently incalculable. Add constraints to keep the value in the region where it can be calculated."); fitMat->data[0] = nan("infeasible"); return; } if (want & FF_COMPUTE_FIT) { double param = (fc->lowerBound? CIElement : -CIElement); if (fc->compositeCIFunction) { double diff = fc->targetFit - fit; diff *= diff; if (diff > 1e2) { // Ensure there aren't any creative solutions diff = nan("infeasible"); return; } fitMat->data[0] = diff + param; } else { fitMat->data[0] = param; } //mxLog("param at %f", fitMat->data[0]); } if (want & (FF_COMPUTE_GRADIENT | FF_COMPUTE_HESSIAN | FF_COMPUTE_IHESSIAN)) { // add deriv adjustments here TODO } }
void FitMultigroup::compute(int want, FitContext *fc) { omxMatrix *fitMatrix = matrix; double fit = 0; double mac = 0; FitMultigroup *mg = (FitMultigroup*) this; for (size_t ex=0; ex < mg->fits.size(); ex++) { omxMatrix* f1 = mg->fits[ex]; if (f1->fitFunction) { omxFitFunctionCompute(f1->fitFunction, want, fc); if (want & FF_COMPUTE_MAXABSCHANGE) { mac = std::max(fc->mac, mac); } if (want & FF_COMPUTE_PREOPTIMIZE) { if (units == FIT_UNITS_UNINITIALIZED) { units = f1->fitFunction->units; } else if (units != f1->fitFunction->units) { mxThrow("%s: cannot combine units %s and %s (from %s)", matrix->name(), fitUnitsToName(units), fitUnitsToName(f1->fitFunction->units), f1->name()); } } } else { omxRecompute(f1, fc); } if (want & FF_COMPUTE_FIT) { if(f1->rows != 1 || f1->cols != 1) { omxRaiseErrorf("%s[%d]: %s of type %s does not evaluate to a 1x1 matrix", fitMatrix->name(), (int)ex, f1->name(), f1->fitFunction->fitType); } fit += f1->data[0]; if (mg->verbose >= 1) { mxLog("%s: %s fit=%f", fitMatrix->name(), f1->name(), f1->data[0]); } } } if (fc) fc->mac = mac; if (want & FF_COMPUTE_FIT) { fitMatrix->data[0] = fit; if (mg->verbose >= 1) { mxLog("%s: fit=%f", fitMatrix->name(), fit); } } }
void omxState::initialRecalc(FitContext *fc) { omxInitialMatrixAlgebraCompute(fc); for(size_t j = 0; j < expectationList.size(); j++) { // TODO: Smarter inference for which expectations to duplicate omxCompleteExpectation(expectationList[j]); } for (int ax=0; ax < (int) algebraList.size(); ++ax) { omxMatrix *matrix = algebraList[ax]; if (!matrix->fitFunction) continue; omxCompleteFitFunction(matrix); omxFitFunctionCompute(matrix->fitFunction, FF_COMPUTE_INITIAL_FIT, fc); } for (size_t xx=0; xx < conListX.size(); ++xx) { conListX[xx]->prep(fc); } }
void state::compute(int want, FitContext *fc) { state *st = (state*) this; auto *oo = this; for (auto c1 : components) { if (c1->fitFunction) { omxFitFunctionCompute(c1->fitFunction, want, fc); } else { omxRecompute(c1, fc); } } if (!(want & FF_COMPUTE_FIT)) return; int nrow = components[0]->rows; for (auto c1 : components) { if (c1->rows != nrow) { mxThrow("%s: component '%s' has %d rows but component '%s' has %d rows", oo->name(), components[0]->name(), nrow, c1->name(), c1->rows); } } Eigen::VectorXd expect; Eigen::VectorXd rowResult; int numC = components.size(); Eigen::VectorXd tp(numC); double lp=0; for (int rx=0; rx < nrow; ++rx) { if (expectation->loadDefVars(rx) || rx == 0) { omxExpectationCompute(fc, expectation, NULL); if (!st->transition || rx == 0) { EigenVectorAdaptor Einitial(st->initial); expect = Einitial; if (expect.rows() != numC || expect.cols() != 1) { omxRaiseErrorf("%s: initial prob matrix must be %dx%d not %dx%d", name(), numC, 1, expect.rows(), expect.cols()); return; } } if (st->transition && (st->transition->rows != numC || st->transition->cols != numC)) { omxRaiseErrorf("%s: transition prob matrix must be %dx%d not %dx%d", name(), numC, numC, st->transition->rows, st->transition->cols); return; } } for (int cx=0; cx < int(components.size()); ++cx) { EigenVectorAdaptor Ecomp(components[cx]); tp[cx] = Ecomp[rx]; } if (st->verbose >= 4) { mxPrintMat("tp", tp); } if (st->transition) { EigenMatrixAdaptor Etransition(st->transition); expect = (Etransition * expect).eval(); } rowResult = tp.array() * expect.array(); double rowp = rowResult.sum(); rowResult /= rowp; lp += log(rowp); if (st->transition) expect = rowResult; } oo->matrix->data[0] = Global->llScale * lp; if (st->verbose >= 2) mxLog("%s: fit=%f", oo->name(), lp); }