Allow ComputeIterate to test maximum absolute change
[openmx:openmx.git] / src / omxFIMLFitFunction.cpp
1 /*
2  *  Copyright 2007-2013 The OpenMx Project
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 #include <R.h>
18 #include <Rinternals.h>
19 #include <Rdefines.h>
20 #include <R_ext/Rdynload.h>
21 #include <R_ext/BLAS.h>
22 #include <R_ext/Lapack.h>
23 #include "omxDefines.h"
24 #include "omxAlgebraFunctions.h"
25 #include "omxSymbolTable.h"
26 #include "omxData.h"
27 #include "omxFIMLFitFunction.h"
28 #include "omxFIMLSingleIteration.h"
29 #include "omxSadmvnWrapper.h"
30
31 #define max(a,b) \
32    ({ __typeof__ (a) _a = (a); \
33        __typeof__ (b) _b = (b); \
34      _a > _b ? _a : _b; })
35
36 /* FIML Function body */
37 void omxDestroyFIMLFitFunction(omxFitFunction *off) {
38         if(OMX_DEBUG) { mxLog("Destroying FIML fit function object."); }
39         omxFIMLFitFunction *argStruct = (omxFIMLFitFunction*) (off->argStruct);
40
41         if(argStruct->smallMeans != NULL) omxFreeMatrixData(argStruct->smallMeans);
42         if(argStruct->ordMeans != NULL) omxFreeMatrixData(argStruct->ordMeans);
43         if(argStruct->contRow != NULL) omxFreeMatrixData(argStruct->contRow);
44         if(argStruct->ordRow != NULL) omxFreeMatrixData(argStruct->ordRow);
45         if(argStruct->ordCov != NULL) omxFreeMatrixData(argStruct->ordCov);
46         if(argStruct->ordContCov != NULL) omxFreeMatrixData(argStruct->ordContCov);
47         if(argStruct->halfCov != NULL) omxFreeMatrixData(argStruct->halfCov);
48         if(argStruct->reduceCov != NULL) omxFreeMatrixData(argStruct->reduceCov);
49
50         if(argStruct->smallRow != NULL) omxFreeMatrixData(argStruct->smallRow);
51         if(argStruct->smallCov != NULL) omxFreeMatrixData(argStruct->smallCov);
52         if(argStruct->RCX != NULL)              omxFreeMatrixData(argStruct->RCX);
53     if(argStruct->rowLikelihoods != NULL) omxFreeMatrixData(argStruct->rowLikelihoods);
54     if(argStruct->rowLogLikelihoods != NULL) omxFreeMatrixData(argStruct->rowLogLikelihoods);
55         if(off->expectation == NULL) {
56                 if(argStruct->cov != NULL) omxFreeMatrixData(argStruct->cov);
57                 if(argStruct->means != NULL) omxFreeMatrixData(argStruct->means);
58         }
59 }
60
61 void omxPopulateFIMLAttributes(omxFitFunction *off, SEXP algebra) {
62         omxFIMLFitFunction *argStruct = ((omxFIMLFitFunction*)off->argStruct);
63         SEXP expCovExt, expMeanExt, rowLikelihoodsExt;
64         omxMatrix *expCovInt, *expMeanInt, *rowLikelihoodsInt;
65         expCovInt = argStruct->cov;
66         expMeanInt = argStruct->means;
67         rowLikelihoodsInt = argStruct->rowLikelihoods;
68
69         PROTECT(expCovExt = allocMatrix(REALSXP, expCovInt->rows, expCovInt->cols));
70         for(int row = 0; row < expCovInt->rows; row++)
71                 for(int col = 0; col < expCovInt->cols; col++)
72                         REAL(expCovExt)[col * expCovInt->rows + row] =
73                                 omxMatrixElement(expCovInt, row, col);
74         if (expMeanInt != NULL) {
75                 PROTECT(expMeanExt = allocMatrix(REALSXP, expMeanInt->rows, expMeanInt->cols));
76                 for(int row = 0; row < expMeanInt->rows; row++)
77                         for(int col = 0; col < expMeanInt->cols; col++)
78                                 REAL(expMeanExt)[col * expMeanInt->rows + row] =
79                                         omxMatrixElement(expMeanInt, row, col);
80         } else {
81                 PROTECT(expMeanExt = allocMatrix(REALSXP, 0, 0));               
82         }
83         PROTECT(rowLikelihoodsExt = allocVector(REALSXP, rowLikelihoodsInt->rows));
84         for(int row = 0; row < rowLikelihoodsInt->rows; row++)
85                 REAL(rowLikelihoodsExt)[row] = omxMatrixElement(rowLikelihoodsInt, row, 0);
86
87         setAttrib(algebra, install("expCov"), expCovExt);
88         setAttrib(algebra, install("expMean"), expMeanExt);
89         setAttrib(algebra, install("likelihoods"), rowLikelihoodsExt);
90
91         UNPROTECT(3); // expCovExp, expCovInt, rowLikelihoodsExt
92 }
93
94 omxRListElement* omxSetFinalReturnsFIMLFitFunction(omxFitFunction *off, int *numReturns)
95 {
96         // DEPRECATED use omxPopulateFIMLAttributes
97         omxFIMLFitFunction* ofiml = (omxFIMLFitFunction *) (off->argStruct);
98
99         if(!ofiml->returnRowLikelihoods) return NULL;
100
101         omxRListElement *retVal = (omxRListElement*) R_alloc(1, sizeof(omxRListElement));
102         omxData* data = ofiml->data;
103         retVal[0].numValues = data->rows;
104         retVal[0].values = (double*) R_alloc(data->rows, sizeof(double));
105
106         return retVal;
107 }
108
109 void markDefVarDependencies(omxState* os, omxDefinitionVar* defVar) {
110
111         int numDeps = defVar->numDeps;
112         int *deps = defVar->deps;
113
114         for (int i = 0; i < numDeps; i++) {
115                 int value = deps[i];
116
117                 if(value < 0) {
118                         omxMarkDirty(os->matrixList[~value]);
119                 } else {
120                         omxMarkDirty(os->algebraList[value]);
121                 }
122         }
123
124 }
125
126 int handleDefinitionVarList(omxData* data, omxState *state, int row, omxDefinitionVar* defVars, double* oldDefs, int numDefs) {
127
128         if(OMX_DEBUG_ROWS(row)) { mxLog("Processing Definition Vars."); }
129         
130         int numVarsFilled = 0;
131
132         /* Fill in Definition Var Estimates */
133         for(int k = 0; k < numDefs; k++) {
134                 if(defVars[k].source != data) {
135                         error("Internal error: definition variable population into incorrect data source");
136                 }
137                 double newDefVar = omxDoubleDataElement(data, row, defVars[k].column);
138                 if(ISNA(newDefVar)) {
139                         error("Error: NA value for a definition variable is Not Yet Implemented.");
140                 }
141                 if(newDefVar == oldDefs[k]) {
142                         continue;       // NOTE: Potential speedup vs accuracy tradeoff here using epsilon comparison
143                 }
144                 oldDefs[k] = newDefVar;
145                 numVarsFilled++;
146
147                 for(int l = 0; l < defVars[k].numLocations; l++) {
148                         if(OMX_DEBUG_ROWS(row)) {
149                                 mxLog("Populating column %d (value %3.2f) into matrix %d.", defVars[k].column, omxDoubleDataElement(defVars[k].source, row, defVars[k].column), defVars[k].matrices[l]);
150                         }
151                         int matrixNumber = defVars[k].matrices[l];
152                         int matrow = defVars[k].rows[l];
153                         int matcol = defVars[k].cols[l];
154                         omxMatrix *matrix = state->matrixList[matrixNumber];
155                         omxSetMatrixElement(matrix, matrow, matcol, newDefVar);
156                 }
157                 markDefVarDependencies(state, &(defVars[k]));
158         }
159         return numVarsFilled;
160 }
161
162 static void omxCallJointFIMLFitFunction(omxFitFunction *off, int want, FitContext *) {
163         // TODO: Figure out how to give access to other per-iteration structures.
164         // TODO: Current implementation is slow: update by filtering correlations and thresholds.
165         // TODO: Current implementation does not implement speedups for sorting.
166         // TODO: Current implementation may fail on all-continuous-missing or all-ordinal-missing rows.
167         
168         if (want & (FF_COMPUTE_PREOPTIMIZE)) return;
169
170     if(OMX_DEBUG) { 
171             mxLog("Beginning Joint FIML Evaluation.");
172     }
173         // Requires: Data, means, covariances, thresholds
174
175         int numDefs;
176
177         int returnRowLikelihoods = 0;
178
179         omxMatrix *cov, *means, *dataColumns;
180
181         omxThresholdColumn *thresholdCols;
182         omxData* data;
183         
184         omxExpectation* expectation;
185
186         omxFIMLFitFunction* ofiml = ((omxFIMLFitFunction*)off->argStruct);
187         omxMatrix* fitMatrix  = off->matrix;
188         omxState* parentState = fitMatrix->currentState;
189         int numChildren = parentState==globalState? Global->numChildren : 0;
190
191         cov             = ofiml->cov;
192         means           = ofiml->means;
193         data            = ofiml->data;                            //  read-only
194         numDefs         = ofiml->numDefs;                         //  read-only
195         dataColumns     = ofiml->dataColumns;
196         thresholdCols = ofiml->thresholdCols;
197
198         returnRowLikelihoods = ofiml->returnRowLikelihoods;   //  read-only
199         expectation = off->expectation;
200
201
202     if(numDefs == 0) {
203         if(OMX_DEBUG) {mxLog("Precalculating cov and means for all rows.");}
204                 omxExpectationRecompute(expectation);
205                 // MCN Also do the threshold formulae!
206                 
207                 for(int j=0; j < dataColumns->cols; j++) {
208                         int var = omxVectorElement(dataColumns, j);
209                         if(omxDataColumnIsFactor(data, j) && thresholdCols[var].numThresholds > 0) { // j is an ordinal column
210                                 omxMatrix* nextMatrix = thresholdCols[var].matrix;
211                                 omxRecompute(nextMatrix);
212                                 checkIncreasing(nextMatrix, thresholdCols[var].column);
213                                 for(int index = 0; index < numChildren; index++) {
214                                         omxMatrix *target = omxLookupDuplicateElement(parentState->childList[index], nextMatrix);
215                                         omxCopyMatrix(target, nextMatrix);
216                                 }
217             }
218         }
219                 for(int index = 0; index < numChildren; index++) {
220                         omxMatrix *childFit = omxLookupDuplicateElement(parentState->childList[index], fitMatrix);
221                         omxFIMLFitFunction* childOfiml = ((omxFIMLFitFunction*) childFit->fitFunction->argStruct);
222                         omxCopyMatrix(childOfiml->cov, cov);
223                         omxCopyMatrix(childOfiml->means, means);
224                 }
225         if(OMX_DEBUG) { omxPrintMatrix(cov, "Cov"); }
226         if(OMX_DEBUG) { omxPrintMatrix(means, "Means"); }
227     }
228
229         memset(ofiml->rowLogLikelihoods->data, 0, sizeof(double) * data->rows);
230     
231         int parallelism = (numChildren == 0) ? 1 : numChildren;
232
233         if (parallelism > data->rows) {
234                 parallelism = data->rows;
235         }
236
237         if (parallelism > 1) {
238                 int stride = (data->rows / parallelism);
239
240                 #pragma omp parallel for num_threads(parallelism) 
241                 for(int i = 0; i < parallelism; i++) {
242                         omxMatrix *childMatrix = omxLookupDuplicateElement(parentState->childList[i], fitMatrix);
243                         omxFitFunction *childFit = childMatrix->fitFunction;
244                         if (i == parallelism - 1) {
245                                 omxFIMLSingleIterationJoint(childFit, off, stride * i, data->rows - stride * i);
246                         } else {
247                                 omxFIMLSingleIterationJoint(childFit, off, stride * i, stride);
248                         }
249                 }
250
251                 for(int i = 0; i < parallelism; i++) {
252                         if (isErrorRaised(parentState->childList[i])) {
253                                 strncpy(parentState->statusMsg, parentState->childList[i]->statusMsg, MAX_STRING_LEN);
254                         }
255                 }
256
257         } else {
258                 omxFIMLSingleIterationJoint(off, off, 0, data->rows);
259         }
260
261         if(!returnRowLikelihoods) {
262                 double val, sum = 0.0;
263                 // floating-point addition is not associative,
264                 // so we serialized the following reduction operation.
265                 for(int i = 0; i < data->rows; i++) {
266                         val = omxVectorElement(ofiml->rowLogLikelihoods, i);
267 //                      mxLog("%d , %f, %llx\n", i, val, *((unsigned long long*) &val));
268                         sum += val;
269                 }       
270                 if(OMX_VERBOSE || OMX_DEBUG) {mxLog("Total Likelihood is %3.3f", sum);}
271                 omxSetMatrixElement(off->matrix, 0, 0, sum);
272         }
273
274 }
275
276 static void omxCallFIMLFitFunction(omxFitFunction *off, int want, FitContext *) {
277
278         if (want & (FF_COMPUTE_PREOPTIMIZE)) return;
279
280         if(OMX_DEBUG) { mxLog("Beginning FIML Evaluation."); }
281         // Requires: Data, means, covariances.
282         // Potential Problem: Definition variables currently are assumed to be at the end of the data matrix.
283
284         int numDefs, returnRowLikelihoods;      
285         omxExpectation* expectation;
286         
287         omxMatrix *cov, *means;//, *oldInverse;
288         omxData *data;
289
290         omxFIMLFitFunction* ofiml = ((omxFIMLFitFunction*) off->argStruct);
291         omxMatrix* objMatrix  = off->matrix;
292         omxState* parentState = objMatrix->currentState;
293         int numChildren = parentState==globalState? Global->numChildren : 0;
294
295         // Locals, for readability.  Should compile out.
296         cov             = ofiml->cov;
297         means           = ofiml->means;
298         data            = ofiml->data;                            //  read-only
299         numDefs         = ofiml->numDefs;                         //  read-only
300         returnRowLikelihoods = ofiml->returnRowLikelihoods;   //  read-only
301         expectation = off->expectation;
302
303         if(numDefs == 0 && strcmp(expectation->expType, "MxExpectationStateSpace")) {
304                 if(OMX_DEBUG) {mxLog("Precalculating cov and means for all rows.");}
305                 omxExpectationCompute(expectation, NULL);
306                 
307                 for(int index = 0; index < numChildren; index++) {
308                         omxMatrix *childFit = omxLookupDuplicateElement(parentState->childList[index], objMatrix);
309                         omxFIMLFitFunction* childOfiml = ((omxFIMLFitFunction*) childFit->fitFunction->argStruct);
310                         omxCopyMatrix(childOfiml->cov, cov);
311                         omxCopyMatrix(childOfiml->means, means);
312                 }
313
314                 if(OMX_DEBUG) { omxPrintMatrix(cov, "Cov"); }
315                 if(OMX_DEBUG) { omxPrintMatrix(means, "Means"); }
316         }
317
318         memset(ofiml->rowLogLikelihoods->data, 0, sizeof(double) * data->rows);
319     
320         int parallelism = (numChildren == 0) ? 1 : numChildren;
321
322         if (parallelism > data->rows) {
323                 parallelism = data->rows;
324         }
325
326         if (parallelism > 1) {
327                 int stride = (data->rows / parallelism);
328
329                 #pragma omp parallel for num_threads(parallelism) 
330                 for(int i = 0; i < parallelism; i++) {
331                         omxMatrix *childMatrix = omxLookupDuplicateElement(parentState->childList[i], objMatrix);
332                         omxFitFunction *childFit = childMatrix->fitFunction;
333                         if (i == parallelism - 1) {
334                                 omxFIMLSingleIteration(childFit, off, stride * i, data->rows - stride * i);
335                         } else {
336                                 omxFIMLSingleIteration(childFit, off, stride * i, stride);
337                         }
338                 }
339
340                 for(int i = 0; i < parallelism; i++) {
341                         if (isErrorRaised(parentState->childList[i])) {
342                                 strncpy(parentState->statusMsg, parentState->childList[i]->statusMsg, MAX_STRING_LEN);
343                         }
344                 }
345
346         } else {
347                 omxFIMLSingleIteration(off, off, 0, data->rows);
348         }
349
350         if(!returnRowLikelihoods) {
351                 double val, sum = 0.0;
352                 // floating-point addition is not associative,
353                 // so we serialized the following reduction operation.
354                 for(int i = 0; i < data->rows; i++) {
355                         val = omxVectorElement(ofiml->rowLogLikelihoods, i);
356 //                      mxLog("%d , %f, %llx\n", i, val, *((unsigned long long*) &val));
357                         sum += val;
358                 }       
359                 if(OMX_VERBOSE || OMX_DEBUG) {mxLog("Total Likelihood is %3.3f", sum);}
360                 omxSetMatrixElement(off->matrix, 0, 0, sum);
361         }
362 }
363
364 static void omxCallFIMLOrdinalFitFunction(omxFitFunction *off, int want, FitContext *) {
365         if (want & (FF_COMPUTE_PREOPTIMIZE)) return;
366
367         /* TODO: Current implementation is slow: update by filtering correlations and thresholds. */
368         if(OMX_DEBUG) { mxLog("Beginning Ordinal FIML Evaluation.");}
369         // Requires: Data, means, covariances, thresholds
370
371         int numDefs;
372         int returnRowLikelihoods = 0;
373
374         omxMatrix *cov, *means, *dataColumns;
375         omxThresholdColumn *thresholdCols;
376         omxData* data;
377         double *corList, *weights;
378         
379         omxExpectation* expectation;
380
381         omxFIMLFitFunction* ofiml = ((omxFIMLFitFunction*)off->argStruct);
382         omxMatrix* objMatrix  = off->matrix;
383         omxState* parentState = objMatrix->currentState;
384         int numChildren = parentState==globalState? Global->numChildren : 0;
385
386         // Locals, for readability.  Compiler should cut through this.
387         cov             = ofiml->cov;
388         means           = ofiml->means;
389         data            = ofiml->data;
390         dataColumns     = ofiml->dataColumns;
391         numDefs         = ofiml->numDefs;
392
393         corList         = ofiml->corList;
394         weights         = ofiml->weights;
395         thresholdCols = ofiml->thresholdCols;
396         returnRowLikelihoods = ofiml->returnRowLikelihoods;
397         
398         expectation = off->expectation;
399         
400         if(numDefs == 0) {
401                 if(OMX_DEBUG_ALGEBRA) { mxLog("No Definition Vars: precalculating."); }
402                 omxExpectationCompute(expectation, NULL);
403                 for(int j = 0; j < dataColumns->cols; j++) {
404                         if(thresholdCols[j].numThresholds > 0) { // Actually an ordinal column
405                                 omxMatrix* nextMatrix = thresholdCols[j].matrix;
406                                 omxRecompute(nextMatrix);
407                                 checkIncreasing(nextMatrix, thresholdCols[j].column);
408                                 for(int index = 0; index < numChildren; index++) {
409                                         omxMatrix *target = omxLookupDuplicateElement(parentState->childList[index], nextMatrix);
410                                         omxCopyMatrix(target, nextMatrix);
411                                 }
412                         }
413                 }
414                 omxStandardizeCovMatrix(cov, corList, weights); // Calculate correlation and covariance
415                 for(int index = 0; index < numChildren; index++) {
416                         omxMatrix *childFit = omxLookupDuplicateElement(parentState->childList[index], objMatrix);
417                         omxFIMLFitFunction* childOfiml = ((omxFIMLFitFunction*) childFit->fitFunction->argStruct);
418                         omxCopyMatrix(childOfiml->cov, cov);
419                         omxCopyMatrix(childOfiml->means, means);
420                         memcpy(childOfiml->weights, weights, sizeof(double) * cov->rows);
421                         memcpy(childOfiml->corList, corList, sizeof(double) * (cov->rows * (cov->rows - 1)) / 2);
422                 }
423         }
424
425         memset(ofiml->rowLogLikelihoods->data, 0, sizeof(double) * data->rows);
426
427         int parallelism = (numChildren == 0) ? 1 : numChildren;
428
429         if (parallelism > data->rows) {
430                 parallelism = data->rows;
431         }
432
433         if (parallelism > 1) {
434                 int stride = (data->rows / parallelism);
435
436                 #pragma omp parallel for num_threads(parallelism) 
437                 for(int i = 0; i < parallelism; i++) {
438                         omxMatrix *childMatrix = omxLookupDuplicateElement(parentState->childList[i], objMatrix);
439                         omxFitFunction *childFit = childMatrix->fitFunction;
440                         if (i == parallelism - 1) {
441                                 omxFIMLSingleIterationOrdinal(childFit, off, stride * i, data->rows - stride * i);
442                         } else {
443                                 omxFIMLSingleIterationOrdinal(childFit, off, stride * i, stride);
444                         }
445                 }
446
447                 for(int i = 0; i < parallelism; i++) {
448                         if (isErrorRaised(parentState->childList[i])) {
449                                 strncpy(parentState->statusMsg, parentState->childList[i]->statusMsg, MAX_STRING_LEN);
450                         }
451                 }
452
453         } else {
454                 omxFIMLSingleIterationOrdinal(off, off, 0, data->rows);
455         }
456
457         if(!returnRowLikelihoods) {
458                 double val, sum = 0.0;
459                 // floating-point addition is not associative,
460                 // so we serialized the following reduction operation.
461                 for(int i = 0; i < data->rows; i++) {
462                         val = omxVectorElement(ofiml->rowLogLikelihoods, i);
463 //                      mxLog("%d , %f, %llx\n", i, val, *((unsigned long long*) &val));
464                         sum += val;
465                 }       
466                 if(OMX_VERBOSE || OMX_DEBUG) {mxLog("Total Likelihood is %3.3f", sum);}
467                 omxSetMatrixElement(off->matrix, 0, 0, sum);
468         }
469 }
470
471 void omxInitFIMLFitFunction(omxFitFunction* off)
472 {
473         if(OMX_DEBUG) {
474                 mxLog("Initializing FIML fit function function.");
475         }
476         SEXP rObj = off->rObj;
477
478         SEXP nextMatrix;
479         int numOrdinal = 0, numContinuous = 0;
480         omxMatrix *cov, *means;
481
482         omxFIMLFitFunction *newObj = (omxFIMLFitFunction*) R_alloc(1, sizeof(omxFIMLFitFunction));
483         omxExpectation* expectation = off->expectation;
484         if(expectation == NULL) {
485                 omxRaiseError(off->matrix->currentState, -1, "FIML cannot fit without model expectations.");
486                 return;
487         }
488
489         cov = omxGetExpectationComponent(expectation, off, "cov");
490         if(cov == NULL) { 
491                 omxRaiseError(off->matrix->currentState, -1, "No covariance expectation in FIML evaluation.");
492                 return;
493         }
494
495         means = omxGetExpectationComponent(expectation, off, "means");
496         
497         if(means == NULL) { 
498                 omxRaiseError(off->matrix->currentState, -1, "No means model in FIML evaluation.");
499                 return;
500         }
501
502         if(OMX_DEBUG) {
503                 mxLog("FIML Initialization Completed.");
504         }
505         
506     newObj->cov = cov;
507     newObj->means = means;
508     newObj->smallMeans = NULL;
509     newObj->ordMeans   = NULL;
510     newObj->contRow    = NULL;
511     newObj->ordRow     = NULL;
512     newObj->ordCov     = NULL;
513     newObj->ordContCov = NULL;
514     newObj->halfCov    = NULL;
515     newObj->reduceCov  = NULL;
516     
517     /* Set default FitFunction calls to FIML FitFunction Calls */
518         off->computeFun = omxCallFIMLFitFunction;
519         off->fitType = "imxFitFunctionFIML";
520         off->setFinalReturns = omxSetFinalReturnsFIMLFitFunction;
521         off->destructFun = omxDestroyFIMLFitFunction;
522         off->populateAttrFun = omxPopulateFIMLAttributes;
523
524         off->usesChildModels = TRUE;
525
526         if(OMX_DEBUG) {
527                 mxLog("Accessing data source.");
528         }
529         newObj->data = off->expectation->data;
530
531         if(OMX_DEBUG) {
532                 mxLog("Accessing row likelihood option.");
533         }
534         PROTECT(nextMatrix = AS_INTEGER(GET_SLOT(rObj, install("vector")))); // preparing the object by using the vector to populate and the flag
535         newObj->returnRowLikelihoods = INTEGER(nextMatrix)[0];
536         if(newObj->returnRowLikelihoods) {
537            omxResizeMatrix(off->matrix, newObj->data->rows, 1, FALSE); // 1=column matrix, FALSE=discards memory as this is a one time resize
538     }
539     newObj->rowLikelihoods = omxInitMatrix(NULL, newObj->data->rows, 1, TRUE, off->matrix->currentState);
540     newObj->rowLogLikelihoods = omxInitMatrix(NULL, newObj->data->rows, 1, TRUE, off->matrix->currentState);
541         UNPROTECT(1); // nextMatrix
542
543         if(OMX_DEBUG) {
544                 mxLog("Accessing variable mapping structure.");
545         }
546         newObj->dataColumns = off->expectation->dataColumns;
547
548         if(OMX_DEBUG) {
549                 mxLog("Accessing Threshold matrix.");
550         }
551         newObj->thresholdCols = off->expectation->thresholds;
552         numOrdinal = off->expectation->numOrdinal;
553         numContinuous = newObj->dataColumns->cols - off->expectation->numOrdinal;
554
555         omxSetContiguousDataColumns(&(newObj->contiguous), newObj->data, newObj->dataColumns);
556         
557         newObj->numDefs = off->expectation->numDefs;
558         newObj->defVars = off->expectation->defVars;
559         newObj->oldDefs = (double *) R_alloc(newObj->numDefs, sizeof(double));          // Storage for Def Vars
560
561         if(OMX_DEBUG) {
562                 mxLog("Accessing definition variables structure.");
563         }
564         newObj->oldDefs = (double *) R_alloc(newObj->numDefs, sizeof(double));          // Storage for Def Vars
565         memset(newObj->oldDefs, NA_REAL, sizeof(double) * newObj->numDefs);                     // Does this work?
566         // for(nextDef = 0; nextDef < newObj->numDefs; nextDef++) {
567         //      newObj->oldDefs[nextDef] = NA_REAL;                                     // Def Vars default to NA
568         // }
569
570     /* Temporary storage for calculation */
571     int covCols = newObj->cov->cols;
572         if(OMX_DEBUG){mxLog("Number of columns found is %d", covCols);}
573     // int ordCols = omxDataNumFactor(newObj->data);        // Unneeded, since we don't use it.
574     // int contCols = omxDataNumNumeric(newObj->data);
575     newObj->smallRow = omxInitMatrix(NULL, 1, covCols, TRUE, off->matrix->currentState);
576     newObj->smallCov = omxInitMatrix(NULL, covCols, covCols, TRUE, off->matrix->currentState);
577     newObj->RCX = omxInitMatrix(NULL, 1, covCols, TRUE, off->matrix->currentState);
578 //  newObj->zeros = omxInitMatrix(NULL, 1, newObj->cov->cols, TRUE, off->matrix->currentState);
579
580     omxAliasMatrix(newObj->smallCov, newObj->cov);          // Will keep its aliased state from here on.
581     off->argStruct = (void*)newObj;
582
583     if(numOrdinal > 0 && numContinuous <= 0) {
584         if(OMX_DEBUG) {
585             mxLog("Ordinal Data detected.  Using Ordinal FIML.");
586         }
587         newObj->weights = (double*) R_alloc(covCols, sizeof(double));
588         newObj->smallMeans = omxInitMatrix(NULL, covCols, 1, TRUE, off->matrix->currentState);
589         omxAliasMatrix(newObj->smallMeans, newObj->means);
590         newObj->corList = (double*) R_alloc(covCols * (covCols + 1) / 2, sizeof(double));
591         newObj->smallCor = (double*) R_alloc(covCols * (covCols + 1) / 2, sizeof(double));
592         newObj->lThresh = (double*) R_alloc(covCols, sizeof(double));
593         newObj->uThresh = (double*) R_alloc(covCols, sizeof(double));
594         newObj->Infin = (int*) R_alloc(covCols, sizeof(int));
595
596         off->computeFun = omxCallFIMLOrdinalFitFunction;
597     } else if(numOrdinal > 0) {
598         if(OMX_DEBUG) {
599             mxLog("Ordinal and Continuous Data detected.  Using Joint Ordinal/Continuous FIML.");
600         }
601
602         newObj->weights = (double*) R_alloc(covCols, sizeof(double));
603         newObj->smallMeans = omxInitMatrix(NULL, covCols, 1, TRUE, off->matrix->currentState);
604         newObj->ordMeans = omxInitMatrix(NULL, covCols, 1, TRUE, off->matrix->currentState);
605         newObj->contRow = omxInitMatrix(NULL, covCols, 1, TRUE, off->matrix->currentState);
606         newObj->ordRow = omxInitMatrix(NULL, covCols, 1, TRUE, off->matrix->currentState);
607         newObj->ordCov = omxInitMatrix(NULL, covCols, covCols, TRUE, off->matrix->currentState);
608         newObj->ordContCov = omxInitMatrix(NULL, covCols, covCols, TRUE, off->matrix->currentState);
609         newObj->halfCov = omxInitMatrix(NULL, covCols, covCols, TRUE, off->matrix->currentState);
610         newObj->reduceCov = omxInitMatrix(NULL, covCols, covCols, TRUE, off->matrix->currentState);
611         omxAliasMatrix(newObj->smallMeans, newObj->means);
612         omxAliasMatrix(newObj->ordMeans, newObj->means);
613         omxAliasMatrix(newObj->contRow, newObj->smallRow );
614         omxAliasMatrix(newObj->ordRow, newObj->smallRow );
615         omxAliasMatrix(newObj->ordCov, newObj->cov);
616         omxAliasMatrix(newObj->ordContCov, newObj->cov);
617         omxAliasMatrix(newObj->smallMeans, newObj->means);
618         newObj->corList = (double*) R_alloc(covCols * (covCols + 1) / 2, sizeof(double));
619         newObj->lThresh = (double*) R_alloc(covCols, sizeof(double));
620         newObj->uThresh = (double*) R_alloc(covCols, sizeof(double));
621         newObj->Infin = (int*) R_alloc(covCols, sizeof(int));
622
623         off->computeFun = omxCallJointFIMLFitFunction;
624     }
625 }