C:/programs/etirm/src/ICRF_GPCM.cpp

Go to the documentation of this file.
00001 /*! \file ICRF_GPCM.cpp
00002  
00003   \brief
00004   Class for computing item category response function (ICRF) 
00005   and its derivative for the generalized partial credit model.
00006 
00007   Estimation Toolkit for Item Response Models (ETIRM)
00008   http://www.smallwaters.com/software/cpp/etirm.html
00009 
00010   Author(s): 
00011   Werner Wothke, maintenance (http://www.smallwaters.com)
00012   Brad Hanson (http://www.b-a-h.com/)
00013   See the file LICENSE for information on usage and redistribution.
00014 
00015   Copyright (C) 2008, Werner Wothke
00016   Copyright (c) 2000-2002, Bradley A. Hanson
00017  */
00018 
00019 #ifdef ETIRM_NO_DIR_PREFIX
00020 #include "ICRF_GPCM.h"
00021 #else
00022 #include "etirm/ICRF_GPCM.h"
00023 #endif
00024 
00025 #include <cmath> // for exp
00026 #if defined(ETIRM_USE_BOOST_CONFIG) || defined(BOOST_NO_LIMITS)
00027 // If no <limits> header use Boost (http://www.boost.org)
00028 // workaround. This assumes the Boost library is available.
00029 #include <boost/detail/limits.hpp>
00030 #else
00031 #include <limits>
00032 #endif
00033 
00034 #ifdef BOOST_NO_STDC_NAMESPACE
00035 // for compilers which do not put C library functions in std namespace
00036 namespace std
00037 { using ::exp;}
00038 #endif
00039 
00040 namespace etirm
00041 {
00042 
00043   /* \brief
00044    ICRF_GPCM, compute probability of a response in response category
00045    'r' for latent variable value theta.
00046    
00047    \param r   Response category, where a response in the first
00048    response category is mFirstResponse, the response
00049    in the second response category is mFirstResponse+1,
00050    etc.
00051    \param param Vector containing item parameters.
00052    \param theta Latent variable value for which probability is calculated.
00053    
00054    */
00055   Real ICRF_GPCM::ICRF(Response r, const RealVector &param, Real theta) const
00056   {
00057 
00058     Real z = 0.0;
00059     Real num = (r == mFirstResponse) ? 1.0 : -1.0;
00060     Real sum = 1.0;
00061     Real a = param[0];
00062     Response ir = mFirstResponse+1;
00063     RealVector::const_iterator ip = param.begin()+1;
00064     for (int i = mNumCat-1; i--; ++ir, ++ip)
00065     {
00066       z += a * (theta - *ip);
00067       Real ez = std::exp(z);
00068       if (ir == r)
00069         num = ez;
00070 
00071       sum += ez;
00072     }
00073 
00074     return num/sum;
00075 
00076   }
00077 
00078   /*! \brief
00079    OpenICC, compute probability of a correct response for latent
00080    variable value theta, where probability must be in the
00081    open interval (0, 1). This function can be used when the 
00082    logarithm of the probability or logit of the probability
00083    needs to be taken.
00084    
00085    */
00086   Real ICRF_GPCM::OpenICRF(Response r, const RealVector &param, Real theta) const
00087   {
00088 
00089     double prob = ICRF(r, param, theta);
00090 
00091     /* Make sure probability is between 0 and 1 */
00092     if (prob <= 0.0)
00093     {
00094       prob = std::numeric_limits<Real>::min();
00095     }
00096     else if (prob >= 1.0)
00097     {
00098       prob = 1.0 - std::numeric_limits<Real>::epsilon();
00099     }
00100 
00101     return prob;
00102   }
00103 
00104   /*!
00105    ExpZ, compute the terms exp(sum_{k=1}^i z_k), i = 1, mNumCat-1, where
00106    z_k = a * (theta - b_k), a = param[0], b_k = param[k].
00107    These terms are stored in the data member mExpz.
00108    Also store values in data members mDenom and mDenom2.
00109    */
00110   void ICRF_GPCM::ExpZ(const RealVector &param, Real theta)
00111   {
00112     Real a = param[0];
00113 
00114     mExpz[0] = 1.0;
00115     mDenom = 1.0;
00116     RealVector::iterator ie = mExpz.begin()+1;
00117     RealVector::const_iterator ip = param.begin() + 1;
00118     Real num = 0.0;
00119     for (int i = mNumCat-1; i--; ++ip, ++ie)
00120     {
00121       num += a * (theta - *ip);
00122       *ie = std::exp(num);
00123       mDenom += *ie;
00124     }
00125 
00126     mDenom2 = mDenom * mDenom;
00127   }
00128 
00129   /*! 
00130    \brief
00131    ICRFDeriv1, compute first derivatives of ICRF with respect to all parameters.
00132    
00133    Returns derivative with respect to item parameters in
00134    vector deriv.
00135    
00136    The derivative is obtained by computing the derivative of the numerator and
00137    denominator of the ICRF probability separately, and using the formula
00138    for the derivative of a quotient of functions.
00139    
00140    */
00141   void ICRF_GPCM::ICRFDeriv1(Response r, const RealVector &param, Real theta, RealVector &deriv)
00142   {
00143     ExpZ(param, theta);
00144 
00145     Real probnum = mExpz[r - mFirstResponse]; // numerator of ICRF for this response
00146     Real a = param[0];
00147 
00148     /* Derivative with respect to a */
00149     Real du = 0.0;
00150     Real nderiv = 0.0; // derivative of numerator of ICRF
00151     Real dderiv = 0.0; // derivative of denominator of ICRF
00152     RealVector::const_iterator ip = param.begin()+1;
00153     RealVector::const_iterator ie = mExpz.begin()+1;
00154     Response ir = mFirstResponse + 1;
00155     int i;
00156     for (i = mNumCat-1; i--; ++ip, ++ie, ++ir)
00157     {
00158       du += theta - *ip;
00159       dderiv += du * *ie;
00160       if (ir == r)
00161         nderiv = du * *ie;
00162     }
00163     deriv[0] = nderiv * mDenom;
00164     deriv[0] -= probnum * dderiv;
00165     deriv[0] /= mDenom2;
00166 
00167     /* Derivatives with respect to b's. Compute derivative of parameter associated with
00168      the last response category first and work backward. */
00169     ie = mExpz.begin()+mNumCat-1;
00170     RealVector::iterator id = deriv.begin() + mNumCat-1;
00171     dderiv = 0.0;
00172     nderiv = -a * probnum;
00173     ir = mFirstResponse + mNumCat - 1;
00174     for (i = mNumCat-1; i--; --ir, --ie, --id)
00175     {
00176       dderiv += -a * *ie;
00177 
00178       if (ir <= r)
00179         *id = nderiv * mDenom;
00180       else
00181         *id = 0.0;
00182       *id -= probnum * dderiv;
00183       *id /= mDenom2;
00184     }
00185 
00186   }
00187 
00188   /*!
00189    \brief Scale, transform item parameters to new IRT scale
00190    */
00191   void ICRF_GPCM::Scale(Real slope, Real intercept, RealVector &param)
00192   {
00193 
00194     /* Transform the slope parameter */
00195     param[0] /= slope;
00196 
00197     /* Transform intercept parameters */
00198     RealVector::iterator ip = param.begin() + 1;
00199     for (int i = mNumParameters-1; i--; ++ip)
00200     {
00201       *ip *= slope;
00202       *ip += intercept;
00203     }
00204   }
00205 
00206   //! \brief GetAllParameters, copy parameters from estParam to allParam.
00207   void ICRF_GPCM::GetAllParameters(const RealVector &estParam, RealVector &allParam) const
00208   {
00209     if (estParam.size() != mNumParameters || allParam.size() != mNumParameters)
00210     {
00211       throw InvalidArgument("Invalid number of parameters", "ICRF_GPCM::GetAllParameters");
00212     }
00213 
00214     RealVector::iterator ia = allParam.begin();
00215     RealVector::const_iterator ie = estParam.begin();
00216     for (int i = mNumParameters; i--; ++ia, ++ie)
00217     {
00218       *ia = *ie;
00219     }
00220   }
00221 
00222 } // namespace etirm

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