Revert "Add option to checkpoint every evaluation"
[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 #include "omxDefines.h"
24 #include "Eigen/SparseCore"
25 #include "glue.h"
26
27 // See R/MxRunHelperFunctions.R npsolMessages
28 // These are ordered from good to bad so we can use max() on a set
29 // of inform results to obtain a bound on convergence status.
30 typedef int ComputeInform;
31 #define INFORM_UNINITIALIZED -1
32 #define INFORM_CONVERGED_OPTIMUM 0
33 #define INFORM_UNCONVERGED_OPTIMUM 1
34         // The final iterate satisfies the optimality conditions to the accuracy requested,
35         // but the sequence of iterates has not yet converged.
36         // Optimizer was terminated because no further improvement
37         // could be made in the merit function (Mx status GREEN).
38 #define INFORM_LINEAR_CONSTRAINTS_INFEASIBLE 2
39         // The linear constraints and bounds could not be satisfied.
40         // The problem has no feasible solution.
41 #define INFORM_NONLINEAR_CONSTRAINTS_INFEASIBLE 3
42         // The nonlinear constraints and bounds could not be satisfied.
43         // The problem may have no feasible solution.
44 #define INFORM_ITERATION_LIMIT 4
45         // The major iteration limit was reached (Mx status BLUE).
46 #define INFORM_NOT_AT_OPTIMUM 6
47         // The model does not satisfy the first-order optimality conditions (i.e. gradient close to zero)
48         // to the required accuracy, and no improved point for the
49         // merit function could be found during the final linesearch (Mx status RED)
50 #define INFORM_BAD_DERIVATIVES 7
51         // The function derivates returned by funcon or funobj
52         // appear to be incorrect.
53 #define INFORM_INVALID_PARAM 9
54         // An input parameter was invalid'
55
56 enum ComputeInfoMethod {
57         INFO_METHOD_DEFAULT,
58         INFO_METHOD_HESSIAN,
59         INFO_METHOD_SANDWICH,
60         INFO_METHOD_BREAD,
61         INFO_METHOD_MEAT
62 };
63
64 struct HessianBlock {
65         std::vector<int> vars;  // global freeVar ID in order
66         Eigen::MatrixXd mat;    // vars * vars, only upper triangle referenced
67         Eigen::MatrixXd mmat;   // including subblocks
68         Eigen::MatrixXd imat;
69         std::vector< HessianBlock* > subBlocks;
70         bool merge;
71         int useId;
72
73         HessianBlock() : merge(false), useId(0) {}
74         HessianBlock *clone();
75         void addSubBlocks();
76         int estNonZero() const;
77 };
78
79 // The idea of FitContext is to eventually enable fitting from
80 // multiple starting values in parallel.
81
82 class FitContext {
83         static omxFitFunction *RFitFunction;
84
85         FitContext *parent;
86
87         std::vector<HessianBlock*> allBlocks;
88         std::vector<HessianBlock*> mergeBlocks;
89         std::vector<HessianBlock*> blockByVar;
90
91         bool haveSparseHess;
92         Eigen::SparseMatrix<double> sparseHess;
93         bool haveSparseIHess;
94         Eigen::SparseMatrix<double> sparseIHess;
95         int estNonZero;
96         int minBlockSize;
97         int maxBlockSize;
98
99         bool haveDenseHess;
100         Eigen::MatrixXd hess;
101         bool haveDenseIHess;
102         Eigen::MatrixXd ihess;
103         bool ihessFiltered;
104
105         std::string IterationError;
106
107         void analyzeHessian();
108         void analyzeHessianBlock(HessianBlock *hb);
109         void testMerge();
110
111  public:
112         FreeVarGroup *varGroup;
113         size_t numParam;               // cached from varGroup
114         std::vector<int> mapToParent;
115         double mac;
116         double fit;
117         double *est;
118         std::vector<const char*> flavor;
119         Eigen::VectorXd grad;
120         int infoDefinite;
121         double infoCondNum;
122         double *stderrs;   // plural to distinguish from stdio's stderr
123         enum ComputeInfoMethod infoMethod;
124         double *infoA; // sandwich, the bread
125         double *infoB; // sandwich, the meat
126         int iterations;
127         ComputeInform inform;
128         int wanted;
129
130         void init();
131         FitContext(std::vector<double> &startingValues);
132         FitContext(FitContext *parent, FreeVarGroup *group);
133         void allocStderrs();
134         void copyParamToModel(omxState* os, double *at);
135         void copyParamToModel(omxState *os);
136         void copyParamToModel(omxMatrix *mat, double *at);
137         void copyParamToModel(omxMatrix *mat);
138         double *take(int want);
139         void maybeCopyParamToModel(omxState* os);
140         void updateParent();
141         void updateParentAndFree();
142         void log(int what);
143         ~FitContext();
144         
145         // deriv related
146         void clearHessian();
147         void negateHessian();
148         void queue(HessianBlock *hb);
149         void refreshDenseHess();
150         void refreshDenseIHess();
151         void refreshSparseHess();
152         bool refreshSparseIHess();
153         Eigen::VectorXd ihessGradProd();
154         double *getDenseHessUninitialized();
155         double *getDenseIHessUninitialized();
156         double *getDenseHessianish();  // either a Hessian or inverse Hessian, remove TODO
157         void copyDenseHess(double *dest);
158         void copyDenseIHess(double *dest);
159         Eigen::VectorXd ihessDiag();
160         void preInfo();
161         void postInfo();
162         void resetIterationError() { IterationError.clear(); }
163         void recordIterationError(const char* msg, ...) __attribute__((format (printf, 2, 3)));
164
165         std::string getIterationError();
166
167         static void cacheFreeVarDependencies();
168         static void setRFitFunction(omxFitFunction *rff);
169 };
170
171 typedef std::vector< std::pair<int, MxRList*> > LocalComputeResult;
172
173 class omxCompute {
174         int computeId;
175  protected:
176         virtual void reportResults(FitContext *fc, MxRList *slots, MxRList *glob) {};
177         void collectResultsHelper(FitContext *fc, std::vector< omxCompute* > &clist,
178                                   LocalComputeResult *lcr, MxRList *out);
179         static enum ComputeInfoMethod stringToInfoMethod(const char *iMethod);
180  public:
181         const char *name;
182         FreeVarGroup *varGroup;
183         omxCompute();
184         virtual void initFromFrontend(SEXP rObj);
185         void compute(FitContext *fc);
186         virtual void computeImpl(FitContext *fc) {}
187         virtual void collectResults(FitContext *fc, LocalComputeResult *lcr, MxRList *out);
188         virtual ~omxCompute();
189 };
190
191 class Ramsay1975 {
192         // Ramsay, J. O. (1975). Solving Implicit Equations in
193         // Psychometric Data Analysis.  Psychometrika, 40(3), 337-360.
194
195         FitContext *fc;
196         size_t numParam;
197         const char *flavor;
198         int verbose;
199         int boundsHit;
200         double minCaution;
201         double highWatermark;
202         std::vector<int> vars;
203         std::vector<double> prevEst;
204         std::vector<double> prevAdj1;
205         std::vector<double> prevAdj2;
206         bool goingWild;
207
208 public:
209         double maxCaution;
210         double caution;
211
212         Ramsay1975(FitContext *fc, const char *flavor, int verbose, double minCaution);
213         void recordEstimate(int px, double newEst);
214         void apply();
215         void recalibrate(bool *restart);
216         void restart(bool myFault);
217 };
218
219 omxCompute *omxNewCompute(omxState* os, const char *type);
220
221 omxCompute *newComputeGradientDescent();
222 omxCompute *newComputeNumericDeriv();
223 omxCompute *newComputeNewtonRaphson();
224 omxCompute *newComputeConfidenceInterval();
225
226 void omxApproxInvertPosDefTriangular(int dim, double *hess, double *ihess, double *stress);
227 void omxApproxInvertPackedPosDefTriangular(int dim, int *mask, double *packedHess, double *stress);
228 SEXP sparseInvert_wrapper(SEXP mat);
229
230 #endif