Tidy matchCaseInsensitive
[openmx:openmx.git] / src / omxImportFrontendState.c
1 /*
2  *  Copyright 2007-2012 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
21 #include <sys/stat.h>
22 #include <errno.h>
23
24 #include "omxDefines.h"
25 #include "omxState.h"
26 #include "omxGlobalState.h"
27 #include "omxNPSOLSpecific.h"
28
29 /* Outside R Functions */
30 static int isDir(const char *path);
31
32 int matchCaseInsensitive(const char *source, const char *target) {
33         return strcasecmp(source, target) == 0;
34 }
35
36 int omxProcessMxDataEntities(SEXP data) {
37         int errOut = FALSE;
38         SEXP nextLoc;
39         if(OMX_DEBUG) { Rprintf("Processing %d data source(s).\n", length(data));}
40         globalState->numData = length(data);
41         globalState->dataList = (omxData**) R_alloc(length(data), sizeof(omxData*));
42
43         for(int index = 0; index < length(data); index++) {
44                 PROTECT(nextLoc = VECTOR_ELT(data, index));                     // Retrieve the data object
45                 globalState->dataList[index] = omxNewDataFromMxData(NULL, nextLoc, globalState);
46                 if(OMX_DEBUG) {
47                         Rprintf("Data initialized at 0x%0xd = (%d x %d).\n",
48                                 globalState->dataList[index], globalState->dataList[index]->rows, globalState->dataList[index]->cols);
49                 }
50                 UNPROTECT(1); // nextMat
51                 if(globalState->statusCode < 0) {
52                         errOut = TRUE;
53                         globalState->numData = index+1;
54                         break;
55                 }
56         }
57         return(errOut);
58 }
59
60 int omxProcessMxMatrixEntities(SEXP matList) {
61         if(OMX_DEBUG) { Rprintf("Processing %d matrix(ces).\n", length(matList));}
62         int errOut = FALSE;
63         SEXP nextLoc, nextMat;
64         globalState->numMats = length(matList);
65         globalState->matrixList = (omxMatrix**) R_alloc(length(matList), sizeof(omxMatrix*));
66         SEXP matListNames = getAttrib(matList, R_NamesSymbol);
67
68         for(int index = 0; index < length(matList); index++) {
69                 PROTECT(nextLoc = VECTOR_ELT(matList, index));          // This is the matrix + populations
70                 PROTECT(nextMat = VECTOR_ELT(nextLoc, 0));              // The first element of the list is the matrix of values
71                 globalState->matrixList[index] = omxNewMatrixFromRPrimitive(
72                         nextMat, globalState, 1, -index - 1);
73                 globalState->matrixList[index]->name = CHAR(STRING_ELT(matListNames, index));
74                 if(OMX_DEBUG) {
75                         Rprintf("Matrix initialized at 0x%0xd = (%d x %d).\n",
76                                 globalState->matrixList[index], globalState->matrixList[index]->rows, globalState->matrixList[index]->cols);
77                 }
78                 UNPROTECT(2); // nextLoc and nextMat
79                 if(globalState->statusCode < 0) {
80                         if(OMX_DEBUG) { Rprintf("Initialization Error processing %dth matrix.\n", index+1);}
81                         errOut = TRUE;
82                         globalState->numMats = index+1;
83                         break;
84                 }
85         }
86         return(errOut);
87 }
88
89 int omxProcessMxAlgebraEntities(SEXP algList) {
90         int errOut = FALSE;
91         SEXP nextAlgTuple;
92         globalState->numAlgs = length(algList);
93         SEXP algListNames = getAttrib(algList, R_NamesSymbol);
94
95         if(OMX_DEBUG) { Rprintf("Processing %d algebras.\n", globalState->numAlgs); }
96         globalState->algebraList = (omxMatrix**) R_alloc(globalState->numAlgs, sizeof(omxMatrix*));
97
98         for(int index = 0; index < globalState->numAlgs; index++) {
99                 globalState->algebraList[index] = omxInitMatrix(NULL, 0, 0, TRUE, globalState);
100         }
101
102         for(int index = 0; index < globalState->numAlgs; index++) {
103                 PROTECT(nextAlgTuple = VECTOR_ELT(algList, index));             // The next algebra or fit function to process
104                 if(OMX_DEBUG) { Rprintf("Initializing algebra %d at location 0x%0x.\n", index, globalState->algebraList + index); }
105                 if(IS_S4_OBJECT(nextAlgTuple)) {                // This is a fit function object.
106                         omxFillMatrixFromMxFitFunction(globalState->algebraList[index], nextAlgTuple, 1, index);
107                 } else {                                                                // This is an algebra spec.
108                         SEXP initialValue, formula, dependencies;
109                         PROTECT(initialValue = VECTOR_ELT(nextAlgTuple, 0));
110                         omxFillMatrixFromRPrimitive(globalState->algebraList[index],
111                                 initialValue, globalState, 1, index);
112                         UNPROTECT(1);   // initialValue
113                         PROTECT(formula = VECTOR_ELT(nextAlgTuple, 1));
114                         omxFillMatrixFromMxAlgebra(globalState->algebraList[index],
115                                 formula, CHAR(STRING_ELT(algListNames, index)));
116                         UNPROTECT(1);   // formula
117                         PROTECT(dependencies = VECTOR_ELT(nextAlgTuple, 2));
118                         UNPROTECT(1);   // dependencies
119                 }
120                 UNPROTECT(1);   // nextAlgTuple
121                 if(globalState->statusCode < 0) {
122                         if(OMX_DEBUG) { Rprintf("Initialization Error processing %dth algebra.\n", index+1);}
123                         errOut = TRUE;
124                         globalState->numAlgs = index+1;
125                         break;
126                 }
127         }
128         return(errOut);
129 }
130
131 int omxProcessMxExpectationEntities(SEXP expList) {
132         if(OMX_DEBUG) { Rprintf("Initializing %d Model Expectation(s).\n", length(expList));}
133         int errOut = FALSE;
134         SEXP nextExp;
135         globalState->numExpects = length(expList);
136         globalState->expectationList = (omxExpectation**) R_alloc(length(expList), sizeof(omxExpectation*));
137
138         for(int index = 0; index < length(expList); index++) {
139                 PROTECT(nextExp = VECTOR_ELT(expList, index));
140                 globalState->expectationList[index] = omxNewIncompleteExpectation(nextExp, index, globalState);
141                 if(OMX_DEBUG) {
142                         Rprintf("%s incomplete expectation set up at 0x%0xd.\n",
143                                 (globalState->expectationList[index]->expType
144                                         == NULL ? "Untyped" : globalState->expectationList[index]->expType),
145                                          globalState->expectationList[index]);
146                 }
147                 UNPROTECT(1); // nextExp
148                 if(globalState->statusCode < 0) {
149                         if(OMX_DEBUG) { Rprintf("Initialization Error processing %dth Expectation.\n", index+1);}
150                         errOut = TRUE;
151                         globalState->numMats = index+1;
152                         break;
153                 }
154         }
155         return(errOut);
156 }
157
158
159 int omxCompleteMxExpectationEntities() {
160         if(OMX_DEBUG) { Rprintf("Completing %d Model Expectation(s).\n", globalState->numExpects);}
161         int errOut = FALSE;
162         
163         for(int index = 0; index < globalState->numExpects; index++) {
164                 omxCompleteExpectation(globalState->expectationList[index]);
165                 if(OMX_DEBUG) {
166                         Rprintf("%s expectation completed at 0x%0xd.\n",
167                                 (globalState->expectationList[index]->expType
168                                         == NULL ? "Untyped" : globalState->expectationList[index]->expType),
169                                          globalState->expectationList[index]);
170                 }
171                 if(globalState->statusCode < 0) {
172                         if(OMX_DEBUG) { Rprintf("Initialization Error processing %dth Expectation.\n", index+1);}
173                         errOut = TRUE;
174                         globalState->numMats = index+1;
175                         break;
176                 }
177         }
178         return(errOut);
179 }
180
181
182 int omxInitialMatrixAlgebraCompute() {
183         int errOut = FALSE;
184         int numMats = globalState->numMats;
185         int numAlgs = globalState->numAlgs;
186
187         if(OMX_DEBUG) {Rprintf("Completed Algebras and Matrices.  Beginning Initial Compute.\n");}
188         omxStateNextEvaluation(globalState);
189
190         globalState->markMatrices = (int*) R_alloc(numMats + numAlgs, sizeof(int));
191
192         for(int index = 0; index < numMats; index++) {
193                 omxRecompute(globalState->matrixList[index]);
194         }
195
196         for(int index = 0; index < numAlgs; index++) {
197                 omxRecompute(globalState->algebraList[index]);
198         }
199         return(errOut);
200 }
201
202 int omxProcessFitFunction(SEXP fitFunction) {
203         int errOut = FALSE;
204         if(!isNull(fitFunction)) {
205                 if(OMX_DEBUG) { Rprintf("Processing fit function.\n"); }
206                 globalState->fitMatrix = omxNewMatrixFromMxIndex(fitFunction, globalState);
207         } else {
208                 globalState->fitMatrix = NULL;
209                 globalState->numFreeParams = 0;
210         }
211         return(errOut);
212 }
213
214 /*
215 checkpointList is a list().  Each element refers to one checkpointing request.
216 Each interval request is a list of length 5.
217 The first element is an integer that specifies type: 0 = file, 1 = socket, 2=R_connection
218 For a file, the next two are the directory(string)  and file name (string).
219 For a socket, they are server (string) and port number (int).
220 For a connection, the next one is the R_connection SEXP object.
221 After that is an integer <type> specifier.  0 means minutes, 1 means iterations.
222 The last element is an integer count, indicating the number of <type>s per checkpoint.
223 */
224 void omxProcessCheckpointOptions(SEXP checkpointList) {
225         if(OMX_VERBOSE) { Rprintf("Processing Checkpoint Requests.\n");}
226         globalState->numCheckpoints = length(checkpointList);
227         if(OMX_DEBUG) {Rprintf("Found %d checkpoints.\n", globalState->numCheckpoints); }
228         globalState->checkpointList = (omxCheckpoint*) R_alloc(globalState->numCheckpoints, sizeof(omxCheckpoint));
229         SEXP nextLoc;
230
231         for(int index = 0; index < globalState->numCheckpoints; index++) {
232                 omxCheckpoint *oC = &(globalState->checkpointList[index]);
233
234                 /* Initialize Checkpoint object */
235                 oC->socket = -1;
236                 oC->file = NULL;
237                 oC->connection = NULL;
238                 oC->time = 0;
239                 oC->numIterations = 0;
240                 oC->lastCheckpoint = 0;
241
242                 const char *pathName, *fileName;
243                 const char __attribute__((unused)) *serverName;
244
245                 PROTECT(nextLoc = VECTOR_ELT(checkpointList, index));
246                 int next = 0;
247                 oC->type = INTEGER(VECTOR_ELT(nextLoc, next++))[0];
248                 switch(oC->type) {
249                 case OMX_FILE_CHECKPOINT:
250                         pathName = CHAR(STRING_ELT(VECTOR_ELT(nextLoc, next++), 0));                    // FIXME: Might need PROTECT()ion
251                         fileName = CHAR(STRING_ELT(VECTOR_ELT(nextLoc, next++), 0));
252                         char sep ='/';
253
254                         if(!isDir(pathName)) {
255                                 error("Unable to open directory %s for checkpoint storage.\n", pathName);
256                         }
257
258                         char* fullname = Calloc(strlen(pathName) + strlen(fileName) + 5, char);
259                         sprintf(fullname, "%s%c%s", pathName, sep, fileName);
260                         if(OMX_VERBOSE) { Rprintf("Opening File: %s\n", fullname); }
261                         oC->file = fopen(fullname, "w");
262                         if(!oC->file) {
263                                 error("Unable to open file %s for checkpoint storage: %s.\n", fullname, strerror(errno));
264                         }
265                         Free(fullname);
266                         oC->saveHessian = FALSE;        // TODO: Decide if this should be true.
267                         break;
268
269                 case OMX_SOCKET_CHECKPOINT:
270                         serverName = CHAR(VECTOR_ELT(nextLoc, next++));
271                         int __attribute__((unused)) portno = INTEGER(AS_INTEGER(VECTOR_ELT(nextLoc, next++)))[0];
272                         Rprintf("Warning NYI: Socket checkpoints Not Yet Implemented.\n");
273                         oC->saveHessian = FALSE;
274                         break;
275
276                 case OMX_CONNECTION_CHECKPOINT: // NYI :::DEBUG:::
277                         oC->connection = VECTOR_ELT(nextLoc, next++);
278                         Rprintf("Warning NYI: Socket checkpoints Not Yet Implemented.\n");
279                         oC->saveHessian = FALSE;
280                         break;
281                 }
282
283                 int isCount = INTEGER(VECTOR_ELT(nextLoc, next++))[0];
284                 if(isCount) {
285                         oC->numIterations = INTEGER(AS_INTEGER(VECTOR_ELT(nextLoc, next++)))[0];
286                 } else {
287                         oC->time = REAL(AS_NUMERIC(VECTOR_ELT(nextLoc, next++)))[0] * 60;       // Constrained to seconds.
288                         if(oC->time < 1) oC->time = 1;                                                                          // Constrained to at least one.
289                 }
290
291                 UNPROTECT(1); /* nextLoc */
292
293         }
294 }
295
296 /*
297 varList is a list().  Each element of this list corresponds to one free parameter.
298 Each free parameter is a list.  The first element of this list is the lower bound.
299 The second element of the list is the upper bound.  The third element of the list
300 is a vector of mxIndices specifying the dependencies of the free parameter. 
301 The remaining elements of the list are 3-tuples.  These 3-tuples are (mxIndex, row, col).
302 */
303 void omxProcessFreeVarList(SEXP varList, int n) {
304         SEXP nextVar, nextLoc;
305         if(OMX_VERBOSE) { Rprintf("Processing Free Parameters.\n"); }
306         globalState->freeVarList = (omxFreeVar*) R_alloc (n, sizeof (omxFreeVar));                      // Data for replacement of free vars
307         for(int freeVarIndex = 0; freeVarIndex < n; freeVarIndex++) {
308                 int numDeps;
309                 PROTECT(nextVar = VECTOR_ELT(varList, freeVarIndex));
310                 int numLocs = length(nextVar) - 3;
311                 globalState->freeVarList[freeVarIndex].numLocations = numLocs;
312                 globalState->freeVarList[freeVarIndex].matrices = (int*) R_alloc(numLocs, sizeof(int));
313                 globalState->freeVarList[freeVarIndex].row               = (int*) R_alloc(numLocs, sizeof(int));
314                 globalState->freeVarList[freeVarIndex].col               = (int*) R_alloc(numLocs, sizeof(int));
315                 globalState->freeVarList[freeVarIndex].name = CHAR(STRING_ELT(GET_NAMES(varList), freeVarIndex));
316
317                 /* Lower Bound */
318                 PROTECT(nextLoc = VECTOR_ELT(nextVar, 0));                                                      // Position 0 is lower bound.
319                 globalState->freeVarList[freeVarIndex].lbound = REAL(nextLoc)[0];
320                 if(ISNA(globalState->freeVarList[freeVarIndex].lbound)) globalState->freeVarList[freeVarIndex].lbound = NEG_INF;
321                 if(globalState->freeVarList[freeVarIndex].lbound == 0.0) globalState->freeVarList[freeVarIndex].lbound = 0.0;
322                 UNPROTECT(1); // nextLoc
323                 /* Upper Bound */
324                 PROTECT(nextLoc = VECTOR_ELT(nextVar, 1));                                                      // Position 1 is upper bound.
325                 globalState->freeVarList[freeVarIndex].ubound = REAL(nextLoc)[0];
326                 if(ISNA(globalState->freeVarList[freeVarIndex].ubound)) globalState->freeVarList[freeVarIndex].ubound = INF;
327                 if(globalState->freeVarList[freeVarIndex].ubound == 0.0) globalState->freeVarList[freeVarIndex].ubound = -0.0;
328                 UNPROTECT(1); // nextLoc
329
330                 PROTECT(nextLoc = VECTOR_ELT(nextVar, 2));                                                      // Position 2 is a vector of dependencies.
331                 numDeps = LENGTH(nextLoc);
332                 globalState->freeVarList[freeVarIndex].numDeps = numDeps;
333                 globalState->freeVarList[freeVarIndex].deps = (int*) R_alloc(numDeps, sizeof(int));
334                 for(int i = 0; i < numDeps; i++) {
335                         globalState->freeVarList[freeVarIndex].deps[i] = INTEGER(nextLoc)[i];
336                 }
337                 UNPROTECT(1); // nextLoc
338
339
340                 if(OMX_DEBUG) { 
341                         Rprintf("Free parameter %d bounded (%f, %f): %d locations\n", freeVarIndex, 
342                                 globalState->freeVarList[freeVarIndex].lbound, 
343                                 globalState->freeVarList[freeVarIndex].ubound, numLocs);
344                 }
345                 for(int locIndex = 0; locIndex < globalState->freeVarList[freeVarIndex].numLocations; locIndex++) {
346                         PROTECT(nextLoc = VECTOR_ELT(nextVar, locIndex+3));
347                         int* theVarList = INTEGER(nextLoc);                     // These come through as integers.
348
349                         int theMat = theVarList[0];                     // Matrix is zero-based indexed.
350                         int theRow = theVarList[1];                     // Row is zero-based.
351                         int theCol = theVarList[2];                     // Column is zero-based.
352
353                         globalState->freeVarList[freeVarIndex].matrices[locIndex] = theMat;
354                         globalState->freeVarList[freeVarIndex].row[locIndex] = theRow;
355                         globalState->freeVarList[freeVarIndex].col[locIndex] = theCol;
356                         UNPROTECT(1); // nextLoc
357                 }
358                 UNPROTECT(1); // nextVar
359         }
360
361         int numMats = globalState->numMats;
362
363         for(int freeVarIndex = 0; freeVarIndex < n; freeVarIndex++) {
364                 omxFreeVar* freeVar = globalState->freeVarList + freeVarIndex;
365                 int *deps   = freeVar->deps;
366                 int numDeps = freeVar->numDeps;
367                 for (int index = 0; index < numDeps; index++) {
368                         globalState->markMatrices[deps[index] + numMats] = 1;
369                 }
370         }
371
372 }
373
374 /*
375         intervalList is a list().  Each element refers to one confidence interval request.
376         Each interval request is a length 5 vector of REAL.
377         The first three elements are the matrixPointer, Row, and Column of the element
378         for which bounds are to be calculated, and are cast to ints here for speed.
379         The last two are the upper and lower boundaries for the confidence space (respectively).
380 */
381 void omxProcessConfidenceIntervals(SEXP intervalList)  {
382         SEXP nextVar;
383         if(OMX_VERBOSE) { Rprintf("Processing Confidence Interval Requests.\n");}
384         globalState->numIntervals = length(intervalList);
385         if(OMX_DEBUG) {Rprintf("Found %d requests.\n", globalState->numIntervals); }
386         globalState->intervalList = (omxConfidenceInterval*) R_alloc(globalState->numIntervals, sizeof(omxConfidenceInterval));
387         for(int index = 0; index < globalState->numIntervals; index++) {
388                 omxConfidenceInterval *oCI = &(globalState->intervalList[index]);
389                 PROTECT(nextVar = VECTOR_ELT(intervalList, index));
390                 double* intervalInfo = REAL(nextVar);
391                 oCI->matrix = omxNewMatrixFromMxIndex( nextVar, globalState);   // Expects an R object
392                 oCI->row = (int) intervalInfo[1];               // Cast to int in C to save memory/Protection ops
393                 oCI->col = (int) intervalInfo[2];               // Cast to int in C to save memory/Protection ops
394                 oCI->lbound = intervalInfo[3];
395                 oCI->ubound = intervalInfo[4];
396                 UNPROTECT(1);
397                 oCI->max = R_NaReal;                                    // NAs, in case something goes wrong
398                 oCI->min = R_NaReal;
399         }
400         if(OMX_VERBOSE) { Rprintf("Processed.\n"); }
401         if(OMX_DEBUG) { Rprintf("%d intervals requested.\n", globalState->numIntervals); }
402 }
403
404 void omxProcessConstraints(SEXP constraints)  {
405         int ncnln = 0; 
406         if(OMX_VERBOSE) { Rprintf("Processing Constraints.\n");}
407         omxMatrix *arg1, *arg2;
408         SEXP nextVar, nextLoc;
409         globalState->numConstraints = length(constraints);
410         if(OMX_DEBUG) {Rprintf("Found %d constraints.\n", globalState->numConstraints); }
411         globalState->conList = (omxConstraint*) R_alloc(globalState->numConstraints, sizeof(omxConstraint));
412         ncnln = 0;
413         for(int constraintIndex = 0; constraintIndex < globalState->numConstraints; constraintIndex++) {
414                 PROTECT(nextVar = VECTOR_ELT(constraints, constraintIndex));
415                 PROTECT(nextLoc = VECTOR_ELT(nextVar, 0));
416                 arg1 = omxNewMatrixFromMxIndex(nextLoc, globalState);
417                 PROTECT(nextLoc = VECTOR_ELT(nextVar, 1));
418                 arg2 = omxNewMatrixFromMxIndex(nextLoc, globalState);
419                 PROTECT(nextLoc = AS_INTEGER(VECTOR_ELT(nextVar, 2)));
420                 globalState->conList[constraintIndex].opCode = INTEGER(nextLoc)[0];
421                 UNPROTECT(4);
422                 omxMatrix *args[2] = {arg1, arg2};
423                 globalState->conList[constraintIndex].result = omxNewAlgebraFromOperatorAndArgs(10, args, 2, globalState); // 10 = binary subtract
424                 omxRecompute(globalState->conList[constraintIndex].result);
425                 int nrows = globalState->conList[constraintIndex].result->rows;
426                 int ncols = globalState->conList[constraintIndex].result->cols;
427                 globalState->conList[constraintIndex].size = nrows * ncols;
428                 ncnln += globalState->conList[constraintIndex].size;
429         }
430         if(OMX_VERBOSE) { Rprintf("Processed.\n"); }
431         if(OMX_DEBUG) { Rprintf("%d effective constraints.\n", ncnln); }
432         globalState->ncnln = ncnln;
433         globalState->nclin = 0;
434 }
435
436 void omxSetupBoundsAndConstraints(double * bl, double * bu, int n, int nclin) {
437         /* Set min and max limits */
438         for(int index = 0; index < n; index++) {
439                 bl[index] = globalState->freeVarList[index].lbound;                             // -Infinity'd be -10^20.
440                 bu[index] = globalState->freeVarList[index].ubound;                             // Infinity would be at 10^20.
441         }
442
443         for(int index = n; index < n+nclin; index++) {                                          // At present, nclin == 0.
444                 bl[index] = NEG_INF;                                                    // Linear constraints have no bounds.
445                 bu[index] = INF;                                                                // Because there are no linear constraints.
446         }                                                                                                   // But if there were, they would go here.
447
448         int index = n + nclin;
449         for(int constraintIndex = 0; constraintIndex < globalState->numConstraints; constraintIndex++) {                // Nonlinear constraints:
450                 if(OMX_DEBUG) { Rprintf("Constraint %d: ", constraintIndex);}
451                 switch(globalState->conList[constraintIndex].opCode) {
452                 case 0:                                                                 // Less than: Must be strictly less than 0.
453                         if(OMX_DEBUG) { Rprintf("Bounded at (-INF, 0).\n");}
454                         for(int offset = 0; offset < globalState->conList[constraintIndex].size; offset++) {
455                                 bl[index] = NEG_INF;
456                                 bu[index] = -0.0;
457                                 index++;
458                         }
459                         break;
460                 case 1:                                                                 // Equal: Must be roughly equal to 0.
461                         if(OMX_DEBUG) { Rprintf("Bounded at (-0, 0).\n");}
462                         for(int offset = 0; offset < globalState->conList[constraintIndex].size; offset++) {
463                                 bl[index] = -0.0;
464                                 bu[index] = 0.0;
465                                 index++;
466                         }
467                         break;
468                 case 2:                                                                 // Greater than: Must be strictly greater than 0.
469                         if(OMX_DEBUG) { Rprintf("Bounded at (0, INF).\n");}
470                         for(int offset = 0; offset < globalState->conList[constraintIndex].size; offset++) {
471                                 if(OMX_DEBUG) { Rprintf("\tBounds set for constraint %d.%d.\n", constraintIndex, offset);}
472                                 bl[index] = 0.0;
473                                 bu[index] = INF;
474                                 index++;
475                         }
476                         break;
477                 default:
478                         if(OMX_DEBUG) { Rprintf("Bounded at (-INF, INF).\n");}
479                         for(int offset = 0; offset < globalState->conList[constraintIndex].size; offset++) {
480                                 bl[index] = NEG_INF;
481                                 bu[index] = INF;
482                                 index++;
483                         }
484                         break;
485                 }
486         }
487 }
488
489 /*
490 *  Acknowledgement:
491 *  This function is duplicated from the function of the same name in the R source code.
492 *  The function appears in src/main/sysutils.c
493 *  Thanks to Michael Spiegel for finding it.
494 */
495 static int isDir(const char *path)
496 {
497     struct stat sb;
498     int isdir = 0;
499     if(!path) return 0;
500     if(stat(path, &sb) == 0) {
501         isdir = (sb.st_mode & S_IFDIR) > 0; /* is a directory */
502         /* We want to know if the directory is writable by this user,
503            which mode does not tell us */
504         isdir &= (access(path, W_OK) == 0);
505     }
506     return isdir;
507 }
508