Handle model.mat[R,C] labels in BA81 latent distribution
[openmx:openmx.git] / src / omxExpectationBA81.h
1 /*
2   Copyright 2012-2014 Joshua Nathaniel Pritikin and contributors
3
4   This is free software: you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation, either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifndef _OMX_EXPECTATIONBA81_H_
19 #define _OMX_EXPECTATIONBA81_H_
20
21 #include "omxExpectation.h"
22 #include "omxOpenmpWrap.h"
23 #include "ba81quad.h"
24
25 enum expectation_type {
26         EXPECTATION_AUGMENTED, // E-M
27         EXPECTATION_OBSERVED,  // regular
28 };
29
30 template <typename CovType>
31 struct BA81EstepBase {
32         void addRow1(class ifaGroup *state, int px, double *Qweight, double *out);
33 };
34
35 template <typename T, typename CovType>
36 struct BA81Estep : BA81EstepBase<CovType> {
37         std::vector<double> thrExpected;
38
39         void begin(class ifaGroup *state, T extraData);
40         void addRow(class ifaGroup *state, T extraData, int px, double *Qweight, int thrId);
41         void recordTable(class ifaGroup *state, T extraData);
42         bool hasEnd() { return true; }
43 };
44
45 template <typename T>
46 struct BA81LatentFixed {
47         void begin(class ifaGroup *state, T extraData) {}
48         void normalizeWeights(class ifaGroup *state, T extraData, int px, double *Qweight, double weight, int thrid);
49         void end(class ifaGroup *state, T extraData) {};
50         bool hasEnd() { return false; }
51 };
52
53 template <typename T>
54 struct BA81LatentSummary {
55         int numLatents;
56         std::vector<double> thrDweight;
57         std::vector<double> latentDist;
58
59         void begin(class ifaGroup *state, T extraData);
60         void normalizeWeights(class ifaGroup *state, T extraData, int px, double *Qweight, double weight, int thrId);
61         void end(class ifaGroup *state, T extraData);
62         bool hasEnd() { return true; }
63 };
64
65 class BA81Expect {
66  public:
67         class ifaGroup grp;
68         int totalOutcomes() { return grp.totalOutcomes; }
69         const double *itemSpec(int ix) { return grp.spec[ix]; }
70         int numItems() { return grp.numItems(); }
71         int getNumUnique() { return (int) grp.rowMap.size(); }
72         int itemOutcomes(int ix) { return grp.itemOutcomes[ix]; }
73
74         const char *name;              // from omxExpectation
75         double LogLargestDouble;       // should be const but need constexpr
76         double LargestDouble;          // should be const but need constexpr
77
78         // data characteristics
79         omxData *data;
80         double weightSum;              // sum of rowWeight
81
82         // quadrature related
83         struct ba81NormalQuad &getQuad() { return grp.quad; }
84
85         // estimation related
86         omxMatrix *itemParam;
87         double *EitemParam;
88         double SmallestPatternLik;
89         double *expected;                     // totalOutcomes * totalQuadPoints (E-step table)
90         bool expectedUsed;
91         int ElatentVersion;
92
93         omxMatrix *_latentMeanOut;
94         omxMatrix *_latentCovOut;
95         template <typename Tmean, typename Tcov>
96         void getLatentDistribution(FitContext *fc, Eigen::MatrixBase<Tmean> &mean, Eigen::MatrixBase<Tcov> &cov);
97
98         omxMatrix *estLatentMean;
99         omxMatrix *estLatentCov;
100         omxMatrix *numObsMat; // this is dumb
101
102         int itemParamVersion;
103         int latentParamVersion;
104         enum expectation_type type;
105         int verbose;
106         bool debugInternal;
107         struct omxFitFunction *fit;  // weak pointer
108
109         BA81Expect() : grp(Global->numThreads, true) {};
110 };
111
112 template <typename Tmean, typename Tcov>
113 void BA81Expect::getLatentDistribution(FitContext *fc, Eigen::MatrixBase<Tmean> &mean, Eigen::MatrixBase<Tcov> &cov)
114 {
115         mean.derived().resize(grp.maxAbilities);
116         if (!_latentMeanOut) {
117                 mean.setZero();
118         } else {
119                 omxRecompute(_latentMeanOut, FF_COMPUTE_FIT, fc);
120                 memcpy(mean.derived().data(), _latentMeanOut->data, sizeof(double) * grp.maxAbilities);
121         }
122         
123         cov.derived().resize(grp.maxAbilities, grp.maxAbilities);
124         if (!_latentCovOut) {
125                 cov.setIdentity();
126         } else {
127                 omxRecompute(_latentCovOut, FF_COMPUTE_FIT, fc);
128                 memcpy(cov.derived().data(), _latentCovOut->data, sizeof(double) * grp.maxAbilities * grp.maxAbilities);
129         }
130 }
131
132 extern const struct rpf *rpf_model;
133 extern int rpf_numModels;
134
135 void ba81OutcomeProb(BA81Expect *state, double *param, bool wantLog);
136
137 OMXINLINE static void
138 gramProduct(double *vec, size_t len, double *out)
139 {
140         int cell = 0;
141         for (size_t v1=0; v1 < len; ++v1) {
142                 for (size_t v2=0; v2 <= v1; ++v2) {
143                         out[cell] = vec[v1] * vec[v2];
144                         ++cell;
145                 }
146         }
147 }
148
149 void ba81SetupQuadrature(omxExpectation* oo);
150 void ba81LikelihoodSlow2(BA81Expect *state, int px, double *out);
151 void cai2010EiEis(BA81Expect *state, int px, double *lxk, double *Eis, double *Ei);
152 static const double BA81_MIN_VARIANCE = .01;
153
154 #endif