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

Go to the documentation of this file.
00001 /*! \file Item.h
00002 
00003   \brief
00004   Class containing information about an item.
00005 
00006   Estimation Toolkit for Item Response Models (ETIRM)
00007   http://www.smallwaters.com/software/cpp/etirm.html
00008 
00009   Author(s): 
00010   Werner Wothke, maintenance (http://www.smallwaters.com)
00011   Brad Hanson (http://www.b-a-h.com/)
00012   See the file LICENSE for information on usage and redistribution.
00013 
00014   Copyright (C) 2008, Werner Wothke
00015   Copyright (c) 2000-2002, Bradley A. Hanson
00016  */
00017 
00018 #ifndef ETIRM_ITEM_H_
00019 #define ETIRM_ITEM_H_
00020 
00021 #ifdef ETIRM_NO_DIR_PREFIX
00022 #include "etirmtypes.h"
00023 #include "ItemParamPrior.h"
00024 #else
00025 #include "etirm/etirmtypes.h"
00026 #include "etirm/ItemParamPrior.h"
00027 #endif
00028 
00029 #include <string>
00030 #include <iterator>
00031 
00032 namespace etirm
00033 {
00034 
00035   /*! 
00036     \brief
00037     Class (template) containing information about an item.
00038 
00039     \section template_args Template Parameters
00040    
00041     \param L  Type of latent variable.
00042    */
00043   template<class L> class Item
00044   {
00045 
00046 public:
00047     //! Type of latent variable.
00048     typedef L latentvar_type;
00049 
00050     //! Iterator over parameters
00051     typedef RealVector::iterator param_iterator;
00052     
00053     //! Iterator over priors
00054     typedef PriorVector::iterator prior_iterator;
00055 
00056     //! Parameter vector
00057     typedef RealVector param_vector;
00058     
00059     //! Vector of parameter priors
00060     typedef PriorVector prior_vector;
00061 
00062     /*! 
00063       \brief
00064       Item class constructor
00065       
00066         \param[in] nparam Number of item parameters.
00067         \param[in] index  zero-offset index of item in vector of all item responses.
00068         \param[in] nRespCat Number of response categories for the item.
00069      */
00070     Item(int nparam, int index, int nRespCat);  // Corrected spelling of "nRespcat".
00071 
00072     //! Item class destructor
00073     virtual ~Item();
00074 
00075     //! Returns vector of estimated parameters for item.    
00076     RealVector GetParameters() const
00077     {
00078       return mParameterEstimates;
00079     }
00080 
00081 
00082     /*! \brief
00083         Returns all item parameters, including estimated and fixed parameters.
00084         
00085         For example, for a two-parameter logistic model only the a and b parameters
00086         are estimated, but a fixed c parameter could be specified.
00087         This function would return a vector containing the
00088         a, b, and c parameters, where only a and b would be
00089         returned by GetParameters().
00090      */
00091     virtual RealVector GetAllParameters() const
00092     {
00093       return GetParameters();
00094     }
00095     
00096     void SetParameters(const RealVector &param);
00097 
00098 #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
00099     template<class I> void SetParameters(I begin, I end);
00100 #endif
00101 
00102     /*! \brief
00103         Sets all item parameters, including estimated and fixed parameters.
00104         
00105         For example, for a two-parameter logistic model only the a and b parameters
00106         are estimated, but a fixed c parameter could be specified.
00107         This function would set the a and b parameters the same as
00108         SetParameters, but would also set the fixed c parameter. 
00109      */
00110     virtual void SetAllParameters(const RealVector &allParam)
00111     {
00112       SetParameters(allParam);
00113     }
00114 
00115     /*!
00116       \brief
00117       Version of SetAllParameters that uses an iterator range to 
00118       define the sequence of all parameters.
00119      */
00120     template<class I> void SetAllParameters(I begin, I end)
00121     {
00122       RealVector allParam(begin, end);
00123       SetAllParameters(allParam);
00124     }
00125 
00126     PriorVector::iterator PriorsIterator()
00127     {
00128       return mPriors.begin();
00129     }
00130     //!< Returns iterator pointing to the first prior element of the first item parameter
00131 
00132     RealVector::iterator ParametersIterator()
00133     {
00134       return mParameterEstimates.begin();
00135     }
00136     //!< Returns iterator to the estimate of the first parameter
00137 
00138     void SetPriors(PriorVector &priors);
00139     //!< Assigns prior distributions of item parameters.
00140 
00141     //! Returns vector (mPriors) of parameter priors
00142     PriorVector GetPriors()
00143     {
00144       return mPriors;
00145     } // Changed "priors" to "mPriors". ww, 1/10/2008.
00146 
00147     void DeletePriors();
00148     //!< Releases memory for all priors in mPriors
00149 
00150     virtual int NonZeroPriors(RealVector &p) const;
00151 
00152     int NumParameters() const
00153     {
00154       return mNumParameters;
00155     }
00156     //!< Returns the number of parameters of the item
00157 
00158     int NumRespCat() const
00159     {
00160       return mNRespCat;
00161     }
00162     //!< Returns the number of valid response categories for item
00163 
00164     /*! 
00165       \brief
00166       Returns true if response "r" is a valid response for this item,
00167       otherwise return false.
00168       
00169       It is assumed that valid item responses are 
00170       mFirstResponse, mFirstResponse+1, ..., mFirstResponse+NumRespCat()-1.
00171       mNotPresentedResponse is not a valid response.
00172      */ 
00173     bool ValidResponse(Response r) const
00174     {
00175       return ((r >= mFirstResponse) && (r <= LastResponse())) ? true : false;
00176     }
00177     
00178     /*!
00179        \brief
00180        Returns true if "r" is a valid response or is the constant indicating
00181        no response to the item.
00182      */
00183     bool CheckResponse(Response r) const
00184     {
00185       return (ValidResponse(r) || r == notPresentedResponse) ? true : false;
00186     }
00187 
00188     virtual int ScaleParameters(Real slope, Real intercept, bool ignorePriors = false) = 0;
00189     //!< Transforms item parameters to new latent variable scale
00190 
00191     /*!
00192       \brief
00193       Item category response function giving the probability of response r
00194       for the item parameters "parameters" and the latent variable "theta".
00195      */
00196     virtual Real ICRF(Response r, const RealVector &parameters, const L &theta) const = 0;
00197 
00198 
00199 #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
00200     /*!
00201       \brief
00202       Computes the probabilities of all possible responses to the item
00203       for the latent variable "theta" and the item parameters "parameters". 
00204       
00205       Probabilities are stored using iterator iprob, which points to the location 
00206       where the probability for the first response category should be stored.
00207      */
00208     template<class I> void ICRFAll(const RealVector &parameters, const L &theta, I iprob) const;
00209 
00210 #endif
00211 
00212     /*!
00213       \brief
00214       Returns probability of response r for parameter estimates in "mParameterEstimates"
00215       and the latent variable "theta".
00216      */
00217     Real ProbResp(Response r, const L &theta) const
00218     {
00219       return ICRF(r, mParameterEstimates, theta);
00220     }
00221 
00222     /*!
00223       \brief
00224       Computes the probabilities of all possible responses to the item
00225       for the the latent variable "theta". 
00226       
00227       Probabilities are stored using iterator iprob, which points to 
00228       the location where the probability for the first response category 
00229       should be stored.
00230      */
00231     template<class I> void ProbRespAll(const L &theta, I iprob) const
00232     {
00233       ICRFAll<I>(mParameterEstimates, theta, iprob);
00234     }
00235 
00236     /*!
00237       \brief
00238       Returns the normalizing constant used for some IRT models, such 
00239       as D for the 3PL model.
00240      */
00241     virtual Real NormalizingConstant() const
00242     {
00243       return 1.0;
00244     }
00245 
00246     /*!
00247       \brief
00248       Returns index associated with response, where ResponseIndex(firstResponse) == 0, 
00249       ResponseIndex(firstResponse+1) == 1, ..., 
00250       ResponseIndex(firstResponse+NumRespCat()-1) == NumRespCat()-1
00251       
00252       Assumes r is a valid response not equal to notPresentedResponse.
00253      */
00254     int ResponseIndex(const Response r) const
00255     {
00256       return r - mFirstResponse;
00257     }
00258 
00259     /*! 
00260       \brief
00261       Returns response in response category "index".
00262     
00263       Note: This is the inverse of the ResponseIndex function.
00264       It is assumed that index >= 0.
00265      */
00266     Response IndexResponse(const int index) const
00267     {
00268       return mFirstResponse + index;
00269     }
00270 
00271 
00272     int Index() const
00273     {
00274       return mIndex;
00275     }
00276     //!< Returns zero-offset index of item (first item has index 0).
00277 
00278 
00279     virtual std::string ModelName() const = 0;
00280     //!< Returns string containing name of model used for item.
00281 
00282     virtual IRTModel Model() const = 0;
00283     //!< Returns type of model used for item.
00284 
00285     /*!
00286       \brief
00287       Assigns response associated with first response category.
00288       
00289       Responses associated with other response categories are
00290       assumed to mFirstResponse+1, mFirstResponse+2, ...
00291      */
00292     virtual void SetFirstResponse(Response r)
00293     {
00294       mFirstResponse = r;
00295       // Make sure response indicating that item was not taken
00296       // is not a valid response
00297       if (ValidResponse(notPresentedResponse))
00298         throw RuntimeError("Not presented response is in range of valid responses",
00299             "Item::SetFirstResponse");
00300     }
00301 
00302     /*!
00303       \brief
00304       Returns the response corresponding to first response category.
00305       
00306       The response corresponding to the i-th response category
00307       would be FirstResponse() + (i-1).
00308      */
00309     Response FirstResponse() const
00310     {
00311       return mFirstResponse;
00312     }
00313 
00314     Response LastResponse() const
00315     {
00316       return mFirstResponse + NumRespCat() - 1;
00317     }
00318     //!< Returns the response corresponding to last response category.
00319 
00320     /*!
00321       \brief
00322       Returns response that is considered correct for dichotomous items.
00323     
00324       Should be overriden for class representing dichotomous items.
00325      */ 
00326     virtual Response CorrectResponse()
00327     {
00328       // By default throw an exception indicating there no response considered correct
00329       throw RuntimeError("No correct response for item", "Item::CorrectResponse()");
00330       return 0;
00331     }
00332 
00333     /*!
00334       \brief
00335       Returns the response which indicates an item was not presented,
00336       or that the examinee did not respond to the item.
00337      */
00338     static Response NotPresentedResponse()
00339     {
00340       return notPresentedResponse;
00341     }
00342 
00343     /*!
00344       \brief
00345       Returns true if "r" is equal to the constant that represents
00346       no response to the item.
00347      */
00348     static bool IsNoResponse(Response r)
00349     {
00350       return r == notPresentedResponse;
00351     }
00352 
00353     /*!
00354       \brief 
00355       Returns the response associated with the first response category
00356       if SetDefaultFirstResponse is not called.
00357      */
00358     static Response DefaultFirstResponse()
00359     {
00360       return defaultFirstResponse;
00361     }
00362 
00363     /*!
00364       \brief
00365       Assigns response indicating item was not presented.
00366       
00367       This should only be called before any item objects
00368       have been created.
00369      */
00370     static void SetNotPresentedResponse(Response r)
00371     {
00372       notPresentedResponse = r;
00373     }
00374 
00375     static void SetDefaultFirstResponse(Response r)
00376     {
00377       defaultFirstResponse = r;
00378     }
00379     //!< Assigns response used for initial value of mFirstResponse in constructor.
00380 
00381 protected:
00382 
00383     int mIndex;
00384     //!< A zero-based index of the item in the vector of responses to all items.
00385 
00386     int mNumParameters;
00387     //!< Number of item parameters.
00388 
00389     int mNRespCat;
00390     //!< Number of response categories.
00391 
00392     RealVector mParameterEstimates;
00393     //!< Vector of estimated item parameters.
00394 
00395     PriorVector mPriors;
00396     //!< Vector of prior distributions for item parameters.
00397 
00398     /*!
00399       \brief
00400       Response associated with first response category.
00401       
00402       It is assumed that valid responses to the item are
00403       mFirstResponse, mFirstResponse+1, ..., mFirstResponse+NumRespCat()-1
00404      */
00405     Response mFirstResponse;
00406 
00407     // The following static variables must be defined somewhere in a program
00408     // using this class, such as in the file containing the main program.
00409 
00410     /*!
00411       \brief
00412       Response indicating an item was not presented or the examinee
00413       did not respond to the item.
00414      */
00415     static Response notPresentedResponse;
00416 
00417 
00418     static Response defaultFirstResponse;
00419     //!< Default value used for mFirstResponse if SetFirstResponse not called.
00420 
00421 
00422 #ifdef BOOST_MSVC6_MEMBER_TEMPLATES
00423     // Definitions of member templates copied from below for compilers 
00424     // that require member templates to
00425     // be defined in the class definition.
00426 public:
00427     template <class I> void ICRFAll(const RealVector &parameters, const L &theta, I iprob) const
00428     {
00429       Real sum = 0.0;
00430       int n = NumRespCat()-1;
00431       // Compute probabilities for all but last response category
00432       for (int r = 0; r < n; ++r, ++iprob)
00433       {
00434         *iprob = ICRF(IndexResponse(r), parameters, theta);
00435         sum += *iprob;
00436       }
00437       // Probability for last response category
00438       *iprob = 1.0 - sum;
00439 
00440     }
00441 
00442     template <class I> void Item<L>::SetParameters(I begin, I end)
00443     {
00444       typename std::iterator_traits<I>::difference_type n = end - begin;
00445       if (n != NumParameters())
00446         throw InvalidArgument("Wrong number of parameters", "Item::SetParameters");
00447 
00448       param_iterator ip = mParameterEstimates.begin();
00449       while (begin != end)
00450       {
00451         *ip = *begin;
00452         ++begin;
00453         ++ip;
00454       }
00455 
00456     }
00457 
00458 #endif
00459 
00460   };
00461 
00462   /*! Constructor */
00463   template<class L> Item<L>::Item(int nparam, int index, int nRespCat) :
00464     mIndex(index), mNumParameters(nparam), mNRespCat(nRespCat), mParameterEstimates(nparam, 0.0),
00465         mPriors(nparam, (ItemParamPrior *) 0), mFirstResponse(defaultFirstResponse)
00466   {
00467     // Make sure response indicating that item was not taken
00468     // is not a valid response
00469     if (ValidResponse(notPresentedResponse))
00470       throw RuntimeError("Not presented response is in range of valid responses",
00471           "Item::SetFirstResponse");
00472 
00473   }
00474 
00475   /*
00476     \brief
00477     Compute the probabilities of all possible responses to the item
00478     for the value of the latent variable "theta" and item
00479     parameters "parameters". 
00480    
00481     Probabilities are stored using iterator iprob, which points to the 
00482     location where the probability or the first response category should 
00483     be stored.
00484    
00485     A copy of this member template is included in the class definition above
00486     for compilers that do not allow definitions of member templates
00487     outside the class definition. Any changes to this function must
00488     also be made to the copy above.
00489    */
00490 #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
00491   template<class L> template<class I> void Item<L>::ICRFAll(const RealVector &parameters,
00492       const L &theta, I iprob) const
00493   {
00494     Real sum = 0.0;
00495     int n = NumRespCat()-1;
00496     // Compute probabilities for all but last response category
00497     for (int r = 0; r < n; ++r, ++iprob)
00498     {
00499       *iprob = ICRF(IndexResponse(r), parameters, theta);
00500       sum += *iprob;
00501     }
00502     // Probability for last response category
00503     *iprob = 1.0 - sum;
00504 
00505   }
00506 #endif
00507 
00508   /* Destructor */
00509   template<class L> Item<L>::~Item()
00510   {
00511   }
00512 
00513   //! Assigns values of parameter estimates from vector
00514   template<class L> void Item<L>::SetParameters(const RealVector &param)
00515   {
00516     if (param.size() != NumParameters())
00517       throw InvalidArgument("Wrong number of parameters", "Item::SetParameters");
00518 
00519     mParameterEstimates = param;
00520 
00521   }
00522 
00523   //! Assigns values of parameter estimates from iterator range
00524 #ifndef BOOST_MSVC6_MEMBER_TEMPLATES
00525   template<class L> template<class I> void Item<L>::SetParameters(I begin, I end)
00526   {
00527     typename std::iterator_traits<I>::difference_type n = end - begin;
00528     if (n != NumParameters())
00529     throw InvalidArgument("Wrong number of parameters", "Item::SetParameters");
00530 
00531     param_iterator ip = mParameterEstimates.begin();
00532     while (begin != end)
00533     {
00534       *ip = *begin;
00535       ++begin;
00536       ++ip;
00537     }
00538 
00539   }
00540 #endif
00541 
00542   template<class L> void Item<L>::SetPriors(PriorVector &priors)
00543   {
00544     if ( (int)priors.size() != NumParameters()) // Casting first argument to type "int", ww, 3-1-2008.
00545       throw InvalidArgument("Wrong number of priors", "Item::SetPriors");
00546 
00547     mPriors = priors;
00548 
00549   }
00550 
00551   /* Releases memory for all priors */
00552   template<class L> void Item<L>::DeletePriors()
00553   {
00554 
00555     int n = mPriors.size();
00556     PriorVector::iterator i = mPriors.begin();
00557 
00558     while (n--)
00559     {
00560       if (*i != 0)
00561       {
00562         delete *i;
00563         *i = 0;
00564       }
00565       ++i;
00566     }
00567 
00568   }
00569 
00570   /*! 
00571     \brief
00572     Ensures that all priors have non-zero, positive densities.
00573      
00574     If a value of a parameter in param has zero probability in
00575     the prior distribution for the parameter then this functions
00576     changes the parameter prior to a strictly positive density.
00577     
00578     Returns the number of parameters that were changed.
00579    */
00580   template<class L> int Item<L>::NonZeroPriors(RealVector &param) const
00581   {
00582     int n = 0;
00583 
00584     // For each parameter assigns new value to parameter if
00585     // prior density of parameter value is zero.
00586     PriorVector::const_iterator iprior = mPriors.begin();
00587     RealVector::iterator iparam = param.begin();
00588     for (int i=NumParameters(); i--; ++iprior, ++iparam)
00589     {
00590       if (*iprior)
00591       {
00592         Real newparam = (*iprior)->NearestNonZero(*iparam);
00593         if (newparam != *iparam)
00594         {
00595           ++n;
00596           *iparam = newparam;
00597         }
00598       }
00599     }
00600 
00601     return n;
00602 
00603   }
00604 
00605 } // namespace etirm
00606 
00607 #endif // ETIRM_ITEM_H_

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