Remove unused argument from omxResizeMatrix
[openmx:openmx.git] / src / omxRowFitFunction.cpp
1 /*
2  *  Copyright 2007-2014 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 "omxDefines.h"
18 #include "omxAlgebraFunctions.h"
19 #include "omxSymbolTable.h"
20 #include "omxData.h"
21 #include "omxRowFitFunction.h"
22 #include "omxFIMLFitFunction.h"
23
24 void omxDestroyRowFitFunction(omxFitFunction *oo) {
25
26         omxRowFitFunction* argStruct = (omxRowFitFunction*)(oo->argStruct);
27
28         omxFreeMatrix(argStruct->dataRow);
29 }
30
31 void omxCopyMatrixToRow(omxMatrix* source, int row, omxMatrix* target) {
32         
33         int i;
34         for(i = 0; i < source->cols; i++) {
35                 omxSetMatrixElement(target, row, i, omxMatrixElement(source, 0, i));
36         }
37
38 }
39
40 void markDataRowDependencies(omxState* os, omxRowFitFunction* orff) {
41
42         int numDeps = orff->numDataRowDeps;
43         int *deps = orff->dataRowDeps;
44
45         for (int i = 0; i < numDeps; i++) {
46                 int value = deps[i];
47
48                 if(value < 0) {
49                         omxMarkDirty(os->matrixList[~value]);
50                 } else {
51                         omxMarkDirty(os->algebraList[value]);
52                 }
53         }
54
55 }
56
57 void omxRowFitFunctionSingleIteration(omxFitFunction *localobj, omxFitFunction *sharedobj, int rowbegin, int rowcount) {
58
59     omxRowFitFunction* oro = ((omxRowFitFunction*) localobj->argStruct);
60     omxRowFitFunction* shared_oro = ((omxRowFitFunction*) sharedobj->argStruct);
61
62         int numDefs;
63
64     omxMatrix *rowAlgebra, *rowResults;
65     omxMatrix *filteredDataRow, *dataRow, *existenceVector;
66     omxMatrix *dataColumns;
67         omxDefinitionVar* defVars;
68         omxData *data;
69         int isContiguous, contiguousStart, contiguousLength;
70     double* oldDefs;
71     int numCols, numRemoves;
72
73         rowAlgebra          = oro->rowAlgebra;
74         rowResults          = shared_oro->rowResults;
75         data                = oro->data;
76         defVars             = oro->defVars;
77         numDefs             = oro->numDefs;
78     oldDefs         = oro->oldDefs;
79     dataColumns     = oro->dataColumns;
80     dataRow         = oro->dataRow;
81     filteredDataRow = oro->filteredDataRow;
82     existenceVector = oro->existenceVector;
83     
84     isContiguous    = oro->contiguous.isContiguous;
85         contiguousStart = oro->contiguous.start;
86         contiguousLength = oro->contiguous.length;
87
88         numCols = dataColumns->cols;
89         int *toRemove = (int*) malloc(sizeof(int) * dataColumns->cols);
90         int *zeros = (int*) calloc(dataColumns->cols, sizeof(int));
91
92     resetDefinitionVariables(oldDefs, numDefs);
93
94         for(int row = rowbegin; row < data->rows && (row - rowbegin) < rowcount; row++) {
95
96                 // Handle Definition Variables.
97         if(OMX_DEBUG_ROWS(row)) { mxLog("numDefs is %d", numDefs);}
98                 if(numDefs != 0) {              // With defs, just copy repeatedly to the rowResults matrix.
99                         handleDefinitionVarList(data, localobj->matrix->currentState, row, defVars, oldDefs, numDefs);
100                 }
101
102                 omxStateNextRow(localobj->matrix->currentState);                                                // Advance row
103                 
104         // Populate data row
105                 numRemoves = 0;
106         
107                 if (isContiguous) {
108                         omxContiguousDataRow(data, row, contiguousStart, contiguousLength, dataRow);
109                 } else {
110                         omxDataRow(data, row, dataColumns, dataRow);    // Populate data row
111                 }
112
113                 markDataRowDependencies(localobj->matrix->currentState, oro);
114                 
115                 for(int j = 0; j < dataColumns->cols; j++) {
116                         double dataValue = omxVectorElement(dataRow, j);
117                         if(std::isnan(dataValue)) {
118                                 numRemoves++;
119                                 toRemove[j] = 1;
120                 omxSetVectorElement(existenceVector, j, 0);
121                         } else {
122                             toRemove[j] = 0;
123                 omxSetVectorElement(existenceVector, j, 1);
124                         }
125                 }               
126                 // TODO: Determine if this is the correct response.
127                 
128                 if(numRemoves == numCols) {
129                         char *errstr = (char*) calloc(250, sizeof(char));
130                         sprintf(errstr, "Row %d completely missing.  omxRowFitFunction cannot have completely missing rows.", omxDataIndex(data, row));
131                         omxRaiseError(localobj->matrix->currentState, -1, errstr);
132                         free(errstr);
133                         continue;
134                 }
135
136                 omxCopyMatrix(filteredDataRow, dataRow);
137                 omxRemoveRowsAndColumns(filteredDataRow, 0, numRemoves, zeros, toRemove);
138
139                 omxRecompute(rowAlgebra);                                                       // Compute this row
140
141                 omxCopyMatrixToRow(rowAlgebra, omxDataIndex(data, row), rowResults);
142         }
143         free(toRemove);
144         free(zeros);
145 }
146
147 static void omxCallRowFitFunction(omxFitFunction *oo, int want, FitContext *) {
148         if (want & (FF_COMPUTE_PREOPTIMIZE)) return;
149
150     if(OMX_DEBUG) { mxLog("Beginning Row Evaluation.");}
151         // Requires: Data, means, covariances.
152
153         omxMatrix* objMatrix  = oo->matrix;
154         omxState* parentState = objMatrix->currentState;
155         int numChildren = parentState==globalState? Global->numChildren : 0;
156
157     omxMatrix *reduceAlgebra;
158         omxData *data;
159
160     omxRowFitFunction* oro = ((omxRowFitFunction*) oo->argStruct);
161
162         reduceAlgebra   = oro->reduceAlgebra;
163         data                = oro->data;
164
165         /* Michael Spiegel, 7/31/12
166         * The demo "RowFitFunctionSimpleExamples" will fail in the parallel 
167         * Hessian calculation if the resizing operation is performed.
168         *
169         omxMatrix *rowAlgebra, *rowResults
170         rowAlgebra          = oro->rowAlgebra;
171         rowResults          = oro->rowResults;
172
173         if(rowResults->cols != rowAlgebra->cols || rowResults->rows != data->rows) {
174                 if(OMX_DEBUG_ROWS(1)) { 
175                         mxLog("Resizing rowResults from %dx%d to %dx%d.", 
176                                 rowResults->rows, rowResults->cols, 
177                                 data->rows, rowAlgebra->cols); 
178                 }
179                 omxResizeMatrix(rowResults, data->rows, rowAlgebra->cols);
180         }
181         */
182                 
183     int parallelism = (numChildren == 0) ? 1 : numChildren;
184
185         if (parallelism > data->rows) {
186                 parallelism = data->rows;
187         }
188
189         if (parallelism > 1) {
190                 int stride = (data->rows / parallelism);
191
192                 #pragma omp parallel for num_threads(parallelism) 
193                 for(int i = 0; i < parallelism; i++) {
194                         omxMatrix *childMatrix = omxLookupDuplicateElement(parentState->childList[i], objMatrix);
195                         omxFitFunction *childFit = childMatrix->fitFunction;
196                         if (i == parallelism - 1) {
197                                 omxRowFitFunctionSingleIteration(childFit, oo, stride * i, data->rows - stride * i);
198                         } else {
199                                 omxRowFitFunctionSingleIteration(childFit, oo, stride * i, stride);
200                         }
201                 }
202         } else {
203                 omxRowFitFunctionSingleIteration(oo, oo, 0, data->rows);
204         }
205
206         omxRecompute(reduceAlgebra);
207
208         omxCopyMatrix(oo->matrix, reduceAlgebra);
209
210 }
211
212 void omxInitRowFitFunction(omxFitFunction* oo) {
213
214         if(OMX_DEBUG) { mxLog("Initializing Row/Reduce fit function."); }
215
216         SEXP rObj = oo->rObj;
217         SEXP nextMatrix, itemList, nextItem;
218         int nextDef, index, numDeps;
219
220         omxRowFitFunction *newObj = (omxRowFitFunction*) R_alloc(1, sizeof(omxRowFitFunction));
221
222         if(OMX_DEBUG) {mxLog("Accessing data source."); }
223         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("data")));
224         newObj->data = omxDataLookupFromState(nextMatrix, oo->matrix->currentState);
225         if(newObj->data == NULL) {
226                 char *errstr = (char*) calloc(250, sizeof(char));
227                 sprintf(errstr, "No data provided to omxRowFitFunction.");
228                 omxRaiseError(oo->matrix->currentState, -1, errstr);
229                 free(errstr);
230         }
231         Rf_unprotect(1); // nextMatrix
232
233         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("rowAlgebra")));
234         newObj->rowAlgebra = omxMatrixLookupFromState1(nextMatrix, oo->matrix->currentState);
235         if(newObj->rowAlgebra == NULL) {
236                 char *errstr = (char*) calloc(250, sizeof(char));
237                 sprintf(errstr, "No row-wise algebra in omxRowFitFunction.");
238                 omxRaiseError(oo->matrix->currentState, -1, errstr);
239                 free(errstr);
240         }
241         Rf_unprotect(1);// nextMatrix
242
243         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("filteredDataRow")));
244         newObj->filteredDataRow = omxMatrixLookupFromState1(nextMatrix, oo->matrix->currentState);
245         if(newObj->filteredDataRow == NULL) {
246                 char *errstr = (char*) calloc(250, sizeof(char));
247                 sprintf(errstr, "No row results matrix in omxRowFitFunction.");
248                 omxRaiseError(oo->matrix->currentState, -1, errstr);
249                 free(errstr);
250         }
251         // Create the original data row from which to filter.
252     newObj->dataRow = omxInitMatrix(newObj->filteredDataRow->rows, newObj->filteredDataRow->cols, TRUE, oo->matrix->currentState);
253     omxCopyMatrix(newObj->filteredDataRow, newObj->dataRow);
254         Rf_unprotect(1);// nextMatrix
255
256         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("existenceVector")));
257         newObj->existenceVector = omxMatrixLookupFromState1(nextMatrix, oo->matrix->currentState);
258     // Do we allow NULL existence?  (Whoa, man. That's, like, deep, or something.)
259         if(newObj->existenceVector == NULL) {
260                 char *errstr = (char*) calloc(250, sizeof(char));
261                 sprintf(errstr, "No existance matrix in omxRowFitFunction.");
262                 omxRaiseError(oo->matrix->currentState, -1, errstr);
263                 free(errstr);
264         }
265         Rf_unprotect(1);// nextMatrix
266
267
268         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("rowResults")));
269         newObj->rowResults = omxMatrixLookupFromState1(nextMatrix, oo->matrix->currentState);
270         if(newObj->rowResults == NULL) {
271                 char *errstr = (char*) calloc(250, sizeof(char));
272                 sprintf(errstr, "No row results matrix in omxRowFitFunction.");
273                 omxRaiseError(oo->matrix->currentState, -1, errstr);
274                 free(errstr);
275         }
276         Rf_unprotect(1);// nextMatrix
277
278         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("reduceAlgebra")));
279         newObj->reduceAlgebra = omxMatrixLookupFromState1(nextMatrix, oo->matrix->currentState);
280         if(newObj->reduceAlgebra == NULL) {
281                 char *errstr = (char*) calloc(250, sizeof(char));
282                 sprintf(errstr, "No row reduction algebra in omxRowFitFunction.");
283                 omxRaiseError(oo->matrix->currentState, -1, errstr);
284                 free(errstr);
285         }
286         Rf_unprotect(1);// nextMatrix
287         
288         if(OMX_DEBUG) {mxLog("Accessing variable mapping structure."); }
289         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("dataColumns")));
290         newObj->dataColumns = omxNewMatrixFromRPrimitive(nextMatrix, oo->matrix->currentState, 0, 0);
291         if(OMX_DEBUG) { omxPrint(newObj->dataColumns, "Variable mapping"); }
292         Rf_unprotect(1);
293
294         if(OMX_DEBUG) {mxLog("Accessing data row dependencies."); }
295         Rf_protect(nextItem = R_do_slot(rObj, Rf_install("dataRowDeps")));
296         numDeps = LENGTH(nextItem);
297         newObj->numDataRowDeps = numDeps;
298         newObj->dataRowDeps = (int*) R_alloc(numDeps, sizeof(int));
299         for(int i = 0; i < numDeps; i++) {
300                 newObj->dataRowDeps[i] = INTEGER(nextItem)[i];
301         }
302         Rf_unprotect(1);
303
304         if(OMX_DEBUG) {mxLog("Accessing definition variables structure."); }
305         Rf_protect(nextMatrix = R_do_slot(rObj, Rf_install("definitionVars")));
306         newObj->numDefs = Rf_length(nextMatrix);
307         newObj->oldDefs = (double *) R_alloc(newObj->numDefs, sizeof(double));          // Storage for Def Vars
308         if(OMX_DEBUG) {mxLog("Number of definition variables is %d.", newObj->numDefs); }
309         newObj->defVars = (omxDefinitionVar *) R_alloc(newObj->numDefs, sizeof(omxDefinitionVar));
310         for(nextDef = 0; nextDef < newObj->numDefs; nextDef++) {
311                 SEXP dataSource, columnSource, depsSource; 
312
313                 Rf_protect(itemList = VECTOR_ELT(nextMatrix, nextDef));
314                 Rf_protect(dataSource = VECTOR_ELT(itemList, 0));
315                 if(OMX_DEBUG) {mxLog("Data source number is %d.", INTEGER(dataSource)[0]); }
316                 newObj->defVars[nextDef].data = INTEGER(dataSource)[0];
317                 newObj->defVars[nextDef].source = oo->matrix->currentState->dataList[INTEGER(dataSource)[0]];
318                 Rf_protect(columnSource = VECTOR_ELT(itemList, 1));
319                 if(OMX_DEBUG) {mxLog("Data column number is %d.", INTEGER(columnSource)[0]); }
320                 newObj->defVars[nextDef].column = INTEGER(columnSource)[0];
321                 Rf_protect(depsSource = VECTOR_ELT(itemList, 2));
322                 numDeps = LENGTH(depsSource);
323                 newObj->defVars[nextDef].numDeps = numDeps;
324                 newObj->defVars[nextDef].deps = (int*) R_alloc(numDeps, sizeof(int));
325                 for(int i = 0; i < numDeps; i++) {
326                         newObj->defVars[nextDef].deps[i] = INTEGER(depsSource)[i];
327                 }
328                 Rf_unprotect(3); // unprotect dataSource, columnSource, and depsSource
329
330                 newObj->defVars[nextDef].numLocations = Rf_length(itemList) - 3;
331                 newObj->defVars[nextDef].matrices = (int *) R_alloc(Rf_length(itemList) - 3, sizeof(int));
332                 newObj->defVars[nextDef].rows = (int *) R_alloc(Rf_length(itemList) - 3, sizeof(int));
333                 newObj->defVars[nextDef].cols = (int *) R_alloc(Rf_length(itemList) - 3, sizeof(int));
334
335                 for(index = 3; index < Rf_length(itemList); index++) {
336                         Rf_protect(nextItem = VECTOR_ELT(itemList, index));
337                         newObj->defVars[nextDef].matrices[index-3] = INTEGER(nextItem)[0];
338                         newObj->defVars[nextDef].rows[index-3]     = INTEGER(nextItem)[1];
339                         newObj->defVars[nextDef].cols[index-3]     = INTEGER(nextItem)[2];
340                         Rf_unprotect(1); // unprotect nextItem
341                 }
342                 Rf_unprotect(1); // unprotect itemList
343         }
344         Rf_unprotect(1); // unprotect nextMatrix
345         
346         /* Set up data columns */
347         omxSetContiguousDataColumns(&(newObj->contiguous), newObj->data, newObj->dataColumns);
348
349         oo->computeFun = omxCallRowFitFunction;
350         oo->destructFun = omxDestroyRowFitFunction;
351         oo->usesChildModels = TRUE;
352
353         oo->argStruct = (void*) newObj;
354 }
355
356