Enable R_NO_REMAP for a cleaner namespace
[openmx:openmx.git] / src / Compute.h
1 /*
2  *  Copyright 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 #ifndef _OMX_COMPUTE_H_
18 #define _OMX_COMPUTE_H_
19
20 #define R_NO_REMAP
21 #include <R.h>
22 #include <Rinternals.h>
23
24 #include "types.h"
25 #include "glue.h"
26
27 // See R/MxRunHelperFunctions.R npsolMessages
28 enum ComputeInform {
29         INFORM_UNINITIALIZED = -1,
30         INFORM_CONVERGED_OPTIMUM = 0,
31         INFORM_UNCONVERGED_OPTIMUM = 1,
32         // The final iterate satisfies the optimality conditions to the accuracy requested,
33         // but the sequence of iterates has not yet converged.
34         // Optimizer was terminated because no further improvement
35         // could be made in the merit function (Mx status GREEN).
36         INFORM_LINEAR_CONSTRAINTS_INFEASIBLE = 2,
37         // The linear constraints and bounds could not be satisfied.
38         // The problem has no feasible solution.
39         INFORM_NONLINEAR_CONSTRAINTS_INFEASIBLE = 3,
40         // The nonlinear constraints and bounds could not be satisfied.
41         // The problem may have no feasible solution.
42         INFORM_ITERATION_LIMIT = 4,
43         // The major iteration limit was reached (Mx status BLUE).
44         INFORM_NOT_AT_OPTIMUM = 6,
45         // The model does not satisfy the first-order optimality conditions
46         // to the required accuracy, and no improved point for the
47         // merit function could be found during the final linesearch (Mx status RED)
48         INFORM_BAD_DERIVATIVES = 7,
49         // The function derivates returned by funcon or funobj
50         // appear to be incorrect.
51         INFORM_INVALID_PARAM = 9
52         // An input parameter was invalid'
53 };
54
55 enum ComputeInfoMethod {
56         INFO_METHOD_DEFAULT,
57         INFO_METHOD_HESSIAN,
58         INFO_METHOD_SANDWICH,
59         INFO_METHOD_BREAD,
60         INFO_METHOD_MEAT
61 };
62
63 // Used to optimize a sparse Hessian-gradient product
64 struct matrixVectorProdTerm {
65         int hentry;
66         int gentry;
67         int dest;
68         matrixVectorProdTerm() {}
69         matrixVectorProdTerm(int he, int ge, int de) {
70                 hentry=he;
71                 gentry=ge;
72                 dest=de;
73         }
74         bool operator< (const matrixVectorProdTerm &j) const {
75           if (hentry < j.hentry) return true;
76           if (hentry == j.hentry) {
77             if (gentry < j.gentry) return true;
78             if (gentry == j.gentry && dest < j.dest) return true;
79           }
80           return false;
81         };
82         bool operator==(const matrixVectorProdTerm &i) const {
83                 return i.hentry == hentry && i.gentry == gentry && i.dest == dest;
84         }
85 };
86
87 // The idea of FitContext is to eventually enable fitting from
88 // multiple starting values in parallel.
89
90 class FitContext {
91         static omxFitFunction *RFitFunction;
92
93         FitContext *parent;
94
95  public:
96         FreeVarGroup *varGroup;
97         std::vector<int> mapToParent;
98         double sampleSize;
99         double mac;
100         double fit;
101         double *est;
102         int *flavor;
103         //      double *denom;
104         double *grad;
105         double *hess;
106         double *ihess;
107         int infoDefinite;
108         double infoCondNum;
109         double *stderrs;   // plural to distinguish from stdio's stderr
110         std::vector< matrixVectorProdTerm > hgProd;
111         enum ComputeInfoMethod infoMethod;
112         double *infoA; // sandwich, the bread
113         double *infoB; // sandwich, the meat
114         double caution;
115         int iterations;
116         enum ComputeInform inform;
117         int wanted;
118
119         void init();
120         FitContext(std::vector<double> &startingValues);
121         FitContext(FitContext *parent, FreeVarGroup *group);
122         void allocStderrs();
123         bool invertHessian();
124         void fixHessianSymmetry(int want, bool force);
125         void fixHessianSymmetry(int want) { fixHessianSymmetry(want, false); }
126         void copyParamToModel(omxState* os, double *at);
127         void copyParamToModel(omxState *os);
128         void copyParamToModel(omxMatrix *mat, double *at);
129         void copyParamToModel(omxMatrix *mat);
130         double *take(int want);
131         void maybeCopyParamToModel(omxState* os);
132         void updateParent();
133         void updateParentAndFree();
134         void log(const char *where);
135         void log(const char *where, int what);
136         void preInfo();
137         void postInfo();
138         ~FitContext();
139         
140         static void cacheFreeVarDependencies();
141         static void setRFitFunction(omxFitFunction *rff);
142 };
143
144 typedef std::vector< std::pair<int, MxRList*> > LocalComputeResult;
145
146 class omxCompute {
147         int computeId;
148  protected:
149         virtual void reportResults(FitContext *fc, MxRList *slots, MxRList *glob) {};
150         void collectResultsHelper(FitContext *fc, std::vector< omxCompute* > &clist,
151                                   LocalComputeResult *lcr, MxRList *out);
152         static enum ComputeInfoMethod stringToInfoMethod(const char *iMethod);
153  public:
154         FreeVarGroup *varGroup;
155         omxCompute();
156         virtual void initFromFrontend(SEXP rObj);
157         virtual omxFitFunction *getFitFunction() { return NULL; }
158         void compute(FitContext *fc);
159         virtual void computeImpl(FitContext *fc) {}
160         virtual void collectResults(FitContext *fc, LocalComputeResult *lcr, MxRList *out);
161         virtual double getOptimizerStatus() { return NA_REAL; }  // backward compatibility
162         virtual ~omxCompute();
163 };
164
165 class Ramsay1975 {
166         // Ramsay, J. O. (1975). Solving Implicit Equations in
167         // Psychometric Data Analysis.  Psychometrika, 40(3), 337-360.
168
169         FitContext *fc;
170         size_t numParam;
171         int flavor;
172         int verbose;
173         double minCaution;
174         double highWatermark;
175         std::vector<double> prevEst;
176         std::vector<double> prevAdj1;
177         std::vector<double> prevAdj2;
178
179 public:
180         double maxCaution;
181         double caution;
182
183         Ramsay1975(FitContext *fc, int flavor, double caution, int verbose, double minCaution);
184         void recordEstimate(int px, double newEst);
185         void apply();
186         void recalibrate(bool *restart);
187         void restart();
188 };
189
190 class omxCompute *omxNewCompute(omxState* os, const char *type);
191
192 class omxCompute *newComputeGradientDescent();
193 class omxCompute *newComputeNumericDeriv();
194 class omxCompute *newComputeNewtonRaphson();
195
196 void omxApproxInvertPosDefTriangular(int dim, double *hess, double *ihess, double *stress);
197 void omxApproxInvertPackedPosDefTriangular(int dim, int *mask, double *packedHess, double *stress);
198
199 #endif