00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef ETIRM_DISCRETELATENTDIST_H_
00020 #define ETIRM_DISCRETELATENTDIST_H_
00021
00022 #ifdef ETIRM_NO_DIR_PREFIX
00023 #include "etirmtypes.h"
00024 #else
00025 #include "etirm/etirmtypes.h"
00026 #endif
00027
00028 #include <vector>
00029 #include <cmath>
00030
00031 #ifdef BOOST_NO_STDC_NAMESPACE
00032 namespace std { using ::sqrt;}
00033 #endif
00034
00035 namespace etirm
00036 {
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 template <class L> class DiscreteLatentDist
00047 {
00048
00049 public:
00050
00051 typedef L latentvar_type;
00052 typedef std::vector<L> point_container;
00053 typedef typename std::vector<L>::iterator point_iterator;
00054 typedef RealMatrix::row_iterator weight_iterator;
00055
00056
00057 DiscreteLatentDist(int ntheta, int ngroups = 1, bool uniquePoints = false);
00058
00059
00060 DiscreteLatentDist(const DiscreteLatentDist &dist);
00061
00062 point_iterator begin_points(int g = 1);
00063
00064
00065 weight_iterator begin_weights(int g = 1);
00066
00067
00068 int size();
00069
00070
00071 int NumGroups();
00072
00073
00074 int NumGroupsUnique();
00075
00076
00077 void Transform(Real slope, Real intercept);
00078
00079
00080 void Scale(Real mean, Real sd, int group, Real &slope, Real &intercept);
00081
00082
00083 void MeanSD(int group, Real &mean, Real &sd);
00084
00085
00086 virtual Real MStep(const RealVector &eprob, int g);
00087
00088
00089
00090 private:
00091
00092 bool mUniquePoints;
00093
00094
00095 int mNumPoints;
00096
00097
00098 int mNumGroups;
00099
00100
00101 std::vector<L> mPoints;
00102
00103
00104
00105
00106
00107
00108
00109
00110 RealMatrix mWeights;
00111
00112 };
00113
00114
00115 template<class L> DiscreteLatentDist<L>::DiscreteLatentDist(int ntheta, int ngroups,
00116 bool uniquePoints) :
00117 mNumPoints(ntheta), mPoints(ntheta), mWeights(ngroups, ntheta), mUniquePoints(uniquePoints),
00118 mNumGroups(ngroups)
00119 {
00120 if (uniquePoints)
00121 mPoints.resize(ntheta*ngroups);
00122 }
00123
00124
00125 template<class L> DiscreteLatentDist<L>::DiscreteLatentDist(const DiscreteLatentDist &dist) :
00126 mUniquePoints(dist.mUniquePoints), mNumPoints(dist.mNumPoints), mNumGroups(dist.mNumGroups),
00127 mPoints(dist.mPoints), mWeights(dist.mWeights)
00128 {
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 template<class L> inline int DiscreteLatentDist<L>::size()
00140 {
00141 return mNumPoints;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 template<class L> inline int DiscreteLatentDist<L>::NumGroups()
00153 {
00154 return mNumGroups;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 template<class L> inline int DiscreteLatentDist<L>::NumGroupsUnique()
00166 {
00167 return mUniquePoints ? mNumGroups : 1;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 template<class L> inline typename std::vector<L>::iterator DiscreteLatentDist<L>::begin_points(
00183 int g)
00184 {
00185 return mUniquePoints ? (mPoints.begin()+mNumPoints*(g-1)) : mPoints.begin();
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 template<class L> inline typename RealMatrix::row_iterator DiscreteLatentDist<L>::begin_weights(
00201 int g)
00202 {
00203 return mWeights.begin_row(g);
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 template<class L> void DiscreteLatentDist<L>::MeanSD(int group, Real &mean, Real &sd)
00221 {
00222
00223 if (group < 1 || group > mNumGroups)
00224 throw InvalidArgument("Invalid examinee group", "DiscreteLatentDist::MeanSD");
00225
00226 int i;
00227
00228
00229 point_iterator ip = begin_points(group);
00230 weight_iterator iw = begin_weights(group);
00231 mean = 0.0;
00232 for (i = mNumPoints; i--; ++ip, ++iw)
00233 {
00234 mean += *ip * *iw;
00235 }
00236
00237
00238 ip = begin_points(group);
00239 iw = begin_weights(group);
00240 sd = 0.0;
00241 for (i = mNumPoints; i--; ++ip, ++iw)
00242 {
00243 Real dev = *ip - mean;
00244 sd += dev * dev * *iw;
00245 }
00246 sd = std::sqrt(sd);
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 template<class L>
00265 void DiscreteLatentDist<L>::Transform(Real slope, Real intercept)
00266 {
00267
00268 int n, i;
00269
00270 if (mUniquePoints) n = mNumGroups;
00271 else n = 1;
00272
00273
00274 for (int g = 1; g <= n; ++g)
00275 {
00276 point_iterator ip = begin_points(g);
00277 for (i = mNumPoints; i--; ++ip)
00278 {
00279 *ip *= slope;
00280 *ip += intercept;
00281 }
00282 }
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 template<class L>
00306 void DiscreteLatentDist<L>::Scale(Real mean, Real sd, int group,
00307 Real &slope, Real &intercept)
00308 {
00309
00310
00311 if (group < 1 || group> mNumGroups)
00312 throw InvalidArgument("Invalid examinee group", "DiscreteLatentDist::Scale");
00313
00314 Real oldmean;
00315 Real oldsd;
00316 MeanSD(group, oldmean, oldsd);
00317
00318
00319 slope = sd / oldsd;
00320 intercept = mean - slope * oldmean;
00321
00322
00323 Transform(slope, intercept);
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 template<class L>
00342 Real DiscreteLatentDist<L>::MStep(const RealVector &eprob, int g)
00343 {
00344 int ncat = mNumPoints;
00345
00346 if (ncat != eprob.size())
00347 {
00348 throw RuntimeError("Mismatch in number of latent variable points",
00349 "DiscreteLatentDist::MStep");
00350 }
00351
00352 if (g < 1 || g> mNumGroups)
00353 {
00354 throw RuntimeError("Invalid examinee group number",
00355 "DiscreteLatentDist::MStep");
00356 }
00357
00358
00359 RealVector::const_iterator in = eprob.begin();
00360 Real ntot = 0.0;
00361 int i;
00362 for (i = ncat; i--; ++in) ntot += *in;
00363
00364
00365 Real reldiff = 0.0;
00366 Real typicalValue = 1.0 / ncat;
00367 in = eprob.begin();
00368 weight_iterator iw = begin_weights(g);
00369 for (i = ncat; i--; ++in, ++iw)
00370 {
00371 Real old = *iw;
00372 *iw = *in / ntot;
00373
00374
00375 Real d = old - *iw;
00376 Real denom = (*iw < typicalValue) ? typicalValue : *iw;
00377 if (denom != 0.0) d /= denom;
00378 d = (d < 0.0) ? -d : d;
00379 if (reldiff < d) reldiff = d;
00380 }
00381
00382 return reldiff;
00383
00384 }
00385
00386 }
00387
00388 #endif // ETIRM_DISCRETELATENTDIST_H_