C:/programs/etirm/src/ItemPolytomous.h

Go to the documentation of this file.
00001 /*! \file ItemPolytomous.h
00002 
00003   \brief
00004   Class representing a polytomously scored item derived from ItemNR.
00005  
00006   Defines functions used in M-step of EM algorithm to compute item parameter estimates.
00007 
00008   Estimation Toolkit for Item Response Models (ETIRM)
00009   http://www.smallwaters.com/software/cpp/etirm.html
00010 
00011   Author(s): 
00012   Werner Wothke, maintenance (http://www.smallwaters.com)
00013   Brad Hanson (http://www.b-a-h.com/)
00014   See the file LICENSE for information on usage and redistribution.
00015 
00016   Copyright (C) 2008, Werner Wothke
00017   Copyright (c) 2000-2002, Bradley A. Hanson
00018  */
00019 
00020 #ifndef ETIRM_ITEMPOLYTOMOUS_H_
00021 #define ETIRM_ITEMPOLYTOMOUS_H_
00022 
00023 #ifdef ETIRM_NO_DIR_PREFIX
00024 #include "etirmtypes.h"
00025 #include "ItemNR.h"
00026 #else
00027 #include "etirm/etirmtypes.h"
00028 #include "etirm/ItemNR.h"
00029 #endif
00030 
00031 #if defined(ETIRM_USE_BOOST_CONFIG) || defined(BOOST_NO_LIMITS)
00032 // If no <limits> header use Boost (http://www.boost.org)
00033 // workaround. This assumes the Boost library is available.
00034 #include <boost/detail/limits.hpp>
00035 #else
00036 #include <limits>
00037 #endif
00038 
00039 #include <cmath> // for log
00040 #ifdef BOOST_NO_STDC_NAMESPACE
00041 // for compilers which put C library functions in std namespace
00042 namespace std
00043 { using ::log;}
00044 #endif
00045 
00046 namespace etirm
00047 {
00048 
00049   /*!
00050     \brief
00051     Class representing a polytomously scored item derived from ItemNR class.
00052  
00053     Defines functions used in M-step of EM algorithm to compute item parameter estimates.
00054 
00055     \section template_args Template Parameters
00056    
00057     \param LC Type of container holding possible values of the
00058         discrete latent variable.
00059     \param M  Type containing functions defining item characteristic 
00060         response function (ICRF) and derivatives of ICRF.
00061    */
00062   template <class LC, class M> class ItemPolytomous : public ItemNR<LC>
00063   {
00064 
00065 public:
00066 
00067     /*!
00068       \brief
00069       Constructor of polytomous response model class.
00070 
00071       \section template_args Template Parameters
00072    
00073       \param LC Type of container holding possible values of the
00074           discrete latent variable.
00075       \param M  Type containing functions defining item characteristic 
00076           response function (ICRF) and derivatives of ICRF.
00077  
00078       \section function_args Function Parameters
00079 
00080       \param[in] index Zero-offset index of the item in the vector of all item responses.
00081       \param[in]  icrf  Address of item category response function for the model.
00082       \param[in]  dist  Pointer to discrete latent variable points used in calculating the r's.
00083      */
00084     ItemPolytomous(int index, M &icrf, LC *dist);
00085 
00086     //! Deconstructor of polytomous response model class.
00087     virtual ~ItemPolytomous();
00088 
00089     /*!
00090       \brief
00091       Returns a vector of estimated and fixed parameters. 
00092       
00093       The order of the parameters in the vector is determined by the GetAllParameters 
00094       member function of mICRF.
00095      */
00096     virtual RealVector GetAllParameters() const
00097     {
00098       RealVector allParam(mICRF.NumAllParameters());
00099       mICRF.GetAllParameters(ItemNR<LC>::mParameterEstimates, allParam); // Added "ItemNR<LC>::" reference. ww, 1/12/2008.
00100       return allParam;
00101     }
00102 
00103     //! Assigns values of fixed and estimated parameters.
00104     virtual void SetAllParameters(const RealVector &allParam)
00105     {
00106       mICRF.SetAllParameters(allParam.begin(), allParam.end(), ItemNR<LC>::mParameterEstimates);
00107     } // Added "ItemNR<LC>::" reference. ww, 1/12/2008.
00108 
00109 
00110     virtual Real ICRF(const Response r, const RealVector &parameters, const Real &theta) const;
00111 
00112     virtual int ScaleParameters(Real slope, Real intercept, bool ignorePrior = false);
00113     // Transforms parameter estimates to new latent variable scale.
00114 
00115     virtual std::string ModelName() const
00116     {
00117       return mICRF.Name();
00118     }
00119     //!< Returns string containing name of model used for item.
00120 
00121     virtual IRTModel Model() const
00122     {
00123       return mICRF.Model();
00124     }
00125     //!< Returns type of model used for item.
00126 
00127     /*  The following functions provide an interface to minimization routines (such as UNCMIN)
00128      that are used in the M-step to estimates parameters for one item. */
00129 
00130     virtual double f_to_minimize(RealVector &p);
00131 
00132     virtual void gradient(RealVector &p, RealVector &g);
00133 
00134     virtual void hessian(RealVector &/* x */, RealMatrix &/* h */)
00135     {
00136     }
00137 
00138     virtual int HasAnalyticGradient() const
00139     {
00140       return mICRF.GradientDefined();
00141     }
00142 
00143     virtual int HasAnalyticHessian() const
00144     {
00145       return 0;
00146     }
00147 
00148 protected:
00149 
00150     M mICRF;
00151     //!< Object for calculating ICRF and its derivatives.
00152 
00153   };
00154 
00155   /* Constructor  */
00156   template <class LC, class M> ItemPolytomous<LC, M>::ItemPolytomous(int index, M &icrf, LC *dist) :
00157     ItemNR<LC>(icrf.NumParameters(), index, icrf.NumRespCat(), dist), mICRF(icrf)
00158   {
00159     if (ItemNR<LC>::mNRespCat != icrf.NumRespCat()) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00160     {
00161       throw InvalidArgument("Mismatch in number of response categories for item and ICRF",
00162           "ItemPolytomous::ItemPolytomous");
00163     }
00164   }
00165 
00166   /* Destructor */
00167   template <class LC, class M> ItemPolytomous<LC, M>::~ItemPolytomous()
00168   {
00169   }
00170 
00171   /*!
00172     \brief
00173     Returns value of item characteristic curve for response "r", item parameters "parameters", 
00174     and latent variable value "theta".
00175     
00176     \section template_args Template Parameters
00177    
00178     \param LC Type of container holding possible values of the
00179         discrete latent variable.
00180     \param M  Type containing functions defining item characteristic 
00181         response function (ICRF) and derivatives of ICRF.
00182  
00183     \section function_args Function Parameters
00184 
00185     \param[in] r  Response category.
00186     \param[in] &parameters  Item parameter vector.
00187     \param[in] &theta Ability parameter.
00188    */
00189   template <class LC, class M> inline Real ItemPolytomous<LC, M>::ICRF(const Response r,
00190       const RealVector &parameters, const Real &theta) const
00191   {
00192     return mICRF.ICRF(r, parameters, theta);
00193   }
00194 
00195   /*! 
00196     \brief
00197     Function to maximize in M-step.
00198     
00199     \section template_args Template Parameters
00200    
00201     \param LC Type of container holding possible values of the
00202         discrete latent variable.
00203     \param M  Type containing functions defining item characteristic 
00204         response function (ICRF) and derivatives of ICRF.
00205  
00206     \section function_args Function Parameters
00207 
00208     \param[in] &param Address of item parameter vector.
00209     
00210     Note: Technically, negative value of function is being minimized, so the negative function 
00211       value is being returned.
00212    */
00213   template <class LC, class M> double ItemPolytomous<LC, M>::f_to_minimize(RealVector &param)
00214   {
00215     int i, j, grp;
00216     Real value = 0.0;
00217     int ngroups = ItemNR<LC>::mLatentDist->NumGroupsUnique(); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00218 
00219     /* Compute loglikelihood */
00220     for (grp=1; grp<=ngroups; ++grp)
00221     {
00222       Response r = ItemNR<LC>::FirstResponse(); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00223       for (i = ItemNR<LC>::mNRespCat; i--; ++r) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00224       {
00225         typename ItemNR<LC>::r_iterator ir = ItemNR<LC>::RVector(r, grp); // Added "typename" and "ItemNR<LC>::" references. ww, 1/13/2008.
00226         typename ItemNR<LC>::point_iterator it = ItemNR<LC>::mLatentDist->begin_points(grp); // Added "typename" and "ItemNR<LC>::" reference. ww, 1/13/2008.
00227         for (j=ItemNR<LC>::mNumLatentVarCat; j--; ++ir, ++it) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00228         {
00229           Real prob = mICRF.OpenICRF(r, param, *it);
00230           value += *ir * std::log(prob);
00231         }
00232       }
00233     }
00234 
00235     /* Add priors */
00236     PriorVector::const_iterator iprior = ItemNR<LC>::mPriors.begin(); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00237     RealVector::iterator iparam = param.begin();
00238     for (int j = ItemNR<LC>::NumParameters(); j--; ++iprior, ++iparam) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00239     {
00240       if (*iprior)
00241       {
00242         if ((*iprior)->ZeroDensity(*iparam))
00243         {
00244           // If density of prior is zero then log of prior density is
00245           // minus infinity (negative of minus infinity is returned
00246           // because the function is being minimized)
00247           if (std::numeric_limits<Real>::has_infinity)
00248           {
00249             return std::numeric_limits<Real>::infinity();
00250           }
00251           else
00252           {
00253             return std::numeric_limits<Real>::max();
00254           }
00255         }
00256         else
00257         {
00258           value += (*iprior)->LogDensity(*iparam);
00259         }
00260       }
00261     }
00262 
00263     return -value; // return negative value to find minimum rather than maximum
00264   }
00265 
00266   /*!
00267     \brief
00268     Gradient of function to maximize in M-step.
00269     
00270     \section template_args Template Parameters
00271    
00272     \param LC Type of container holding possible values of the
00273         discrete latent variable.
00274     \param M  Type containing functions defining item characteristic 
00275         response function (ICRF) and derivatives of ICRF.
00276  
00277     \section function_args Function Parameters
00278     
00279     \param[in] &param Address of item parameter vector.
00280     \param[out] &g  Address of gradient vector. Gradient values are returned in the vector elements.
00281     
00282     Note: Technically, negative value of function is being minimized, so the negative gradient 
00283       is being returned.
00284    */
00285   template <class LC, class M> void ItemPolytomous<LC, M>::gradient(RealVector &param,
00286       RealVector &g)
00287   {
00288     g = 0.0;
00289     RealVector deriv(ItemNR<LC>::NumParameters(), 0.0); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00290 
00291     int i, j, grp;
00292     int ngroups = ItemNR<LC>::mLatentDist->NumGroupsUnique(); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00293 
00294     for (grp=1; grp<=ngroups; ++grp)
00295     {
00296       Response r = ItemNR<LC>::FirstResponse(); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00297       for (i = ItemNR<LC>::mNRespCat; i--; ++r) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00298       {
00299 
00300         typename ItemNR<LC>::r_iterator ir = ItemNR<LC>::RVector(r, grp); // Added "typename" and "ItemNR<LC>::" references. ww, 1/13/2008.
00301         typename ItemNR<LC>::point_iterator itheta = ItemNR<LC>::mLatentDist->begin_points(grp); // Added "typename" and "ItemNR<LC>::" references. ww, 1/13/2008.
00302         for (j=ItemNR<LC>::mNumLatentVarCat; j--; ++ir, ++itheta) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00303         {
00304           Real t = *ir / mICRF.OpenICRF(r, param, *itheta);
00305 
00306           mICRF.ICRFDeriv1(r, param, *itheta, deriv);
00307 
00308           // use -t since function is to be minimized, not maximized
00309           deriv *= -t;
00310           g += deriv;
00311 
00312         }
00313       }
00314     }
00315 
00316     /* Add priors */
00317     PriorVector::const_iterator iprior = ItemNR<LC>::mPriors.begin(); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00318     RealVector::iterator iparam = param.begin();
00319     RealVector::iterator ig = g.begin();
00320     for (int j = ItemNR<LC>::NumParameters(); j--; ++iprior, ++iparam, ++ig) // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00321     {
00322       // subtract because function is to be minimized
00323       if (*iprior)
00324         *ig -= (*iprior)->DerivLogDensity1(*iparam);
00325     }
00326 
00327   }
00328 
00329   /*!
00330     \brief
00331     Transforms parameter estimates to new latent variable scale.
00332     
00333     Returns 1 if scaling results in invalid parameters. In this case, the parameters
00334       are not modified.
00335 
00336     \section template_args Template Parameters
00337    
00338     \param LC Type of container holding possible values of the
00339         discrete latent variable.
00340     \param M  Type containing functions defining item characteristic 
00341         response function (ICRF) and derivatives of ICRF.
00342  
00343     \section function_args Function Parameters
00344       
00345     \param[in]  slope Scale parameter for transformation.
00346     \param[in]  intercept Intercept parameter for transformation.
00347     \param[in]  ignorePriors  Flag to ignore prior information when checking validity of transformed parameters.
00348    */ 
00349   template <class LC, class M> int ItemPolytomous<LC, M>::ScaleParameters(Real slope,
00350       Real intercept, bool ignorePriors)
00351   {
00352     RealVector scaledParam(ItemNR<LC>::mParameterEstimates); // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00353 
00354     mICRF.Scale(slope, intercept, scaledParam);
00355 
00356     // Check if scaled parameters are valid
00357     if (!(ItemNR<LC>::ValidParameters(scaledParam, ignorePriors)))
00358       return 1; // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00359 
00360     ItemNR<LC>::mParameterEstimates = scaledParam; // Added "ItemNR<LC>::" reference. ww, 1/13/2008.
00361 
00362     return 0;
00363   }
00364 
00365 }
00366 
00367 #endif // ETIRM_ITEMPOLYTOMOUS_H_

Generated on Sat Mar 1 21:40:16 2008 for ETIRM by  doxygen 1.5.4