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

Go to the documentation of this file.
00001 /*! \file swig_etirm.cpp
00002  
00003   \brief
00004   Definitions of functions and classes to generate scripting language wrapper 
00005   functions for ETIRM using SWIG.
00006 
00007   The file swig_etirm_types.h (which is included in swig_etirm.h) must be 
00008   provided which should contain typedef's for the following types:
00009  
00010   ResponseVector  Vector containing item responses.
00011   item_type   Item class.
00012   examinee_type Examinee class.
00013   lvdist_type   Latent variable distribution class.
00014   random_type   Type of random number generator used for bootstrap.
00015 
00016   For example:
00017 
00018   // Do not process with SWIG, SWIG cannot handle the template arguments
00019   xx_ifndef SWIG
00020  
00021   // Vector of item responses
00022   typedef std::vector<etirm::Response> ResponseVector;
00023  
00024   // Class to hold information about discrete latent variable distribution
00025   typedef etirm::DiscreteLatentDist<etirm::Real> lvdist_type;
00026  
00027   // Class to hold information about examinees
00028   typedef etirm::ExamineeGrpCov<ResponseVector, etirm::RealVector> examinee_type;
00029  
00030   // Type used for array of items. Using ItemNR allows different items to be modeled
00031   // by different classes descendent from ItemNR (e.g., the 3PL model could be used for
00032   // some items, and the 2PL model used for other items).
00033   typedef etirm::ItemNR<lvdist_type> item_type;
00034  
00035   // Use the Mersenne Twister (http://www.math.keio.ac.jp/matumoto/emt.html)
00036   // from the Boost random number library
00037   // (http://www.boost.org/libs/random/index.html) 
00038   // as random number generator for bootstrap samples.
00039   typedef boost::mt19937 random_type;
00040 
00041   xx_endif // SWIG
00042  
00043   An application using these wrapper functions should declare a subclass
00044   of SwigEtirmRun whose constructor initializes the item object pointers, and 
00045   assigns them to the 'items' data member of SwigEtirmRun. 
00046   An application should provide functions for creating and deleting an object
00047   that is a subclass of SwigEtirmRun which is stored in the global variable
00048   gEtirmRun defined in this file.
00049 
00050   Definitions of the function CheckRunInit must be provided. This
00051   function is declared in swig_etirm.h, but each application must define it.
00052   It is not defined in swig_etirm.cpp.
00053  
00054   The function CheckRunInit checks whether gEtirmRun has been
00055   initialized, and if not throws an exception. The message contained
00056   in the exception will differ for different applications. 
00057 
00058   Estimation Toolkit for Item Response Models (ETIRM)
00059   http://www.smallwaters.com/software/cpp/etirm.html
00060 
00061   Author(s): 
00062   Werner Wothke, maintenance (http://www.smallwaters.com)
00063   Brad Hanson (http://www.b-a-h.com/)
00064   See the file LICENSE for information on usage and redistribution.
00065 
00066   Copyright (C) 2008, Werner Wothke
00067   Copyright (c) 2000-2002, Bradley A. Hanson
00068  */
00069 
00070 #ifdef ETIRM_NO_DIR_PREFIX
00071 #include "swig_etirm.h"
00072 #include "MStepIRT.h"
00073 #include "DiscreteNormalDist.h"
00074 #include "ItemParamPriorBeta4.h"
00075 #include "ItemParamPriorLogNormal.h"
00076 #include "ItemParamPriorNormal.h"
00077 #include "BootstrapSample.h"
00078 #include "SimulateResponses.h"
00079 #include "ExamineeThetaMLE.h"
00080 #else
00081 #include "etirm/swig_etirm.h"
00082 #include "etirm/MStepIRT.h"
00083 #include "etirm/DiscreteNormalDist.h"
00084 #include "etirm/ItemParamPriorBeta4.h"
00085 #include "etirm/ItemParamPriorLogNormal.h"
00086 #include "etirm/ItemParamPriorNormal.h"
00087 #include "etirm/BootstrapSample.h"
00088 #include "etirm/SimulateResponses.h"
00089 #include "etirm/ExamineeThetaMLE.h"
00090 #endif
00091 
00092 // Use integer random number generator from boost library
00093 // (http://www.boost.org).
00094 #include <boost/random/uniform_int.hpp>
00095 
00096 #include <cstdio>  // sprintf prototype
00097 // for compilers which do not put C library functions in std namespace
00098 #ifdef BOOST_NO_STDC_NAMESPACE
00099 namespace std
00100 { using ::sprintf;}
00101 #endif
00102 
00103 // Definitions not wrapped by SWIG
00104 namespace etirm
00105 {
00106 
00107   //! Global variable holding information about a run.
00108   SwigEtirmRun *gEtirmRun = 0;
00109 
00110   /*!
00111     \brief
00112     Increments counts based on item response.
00113    
00114     \section function_args Function Parameters
00115    
00116     \param[in]  respIndex "One" offset index corresponding to response to increment 
00117         count for (1 = first response category, 2 = second response category, etc.).
00118     \param[in]  count   Amount to increment counts.
00119     \param[in]  group   Group to increment counts for (1, 2, ...).
00120    */
00121   void ItemRespCounts::AddResponse(int respIndex, Real count, int group)
00122   {
00123 
00124     if (respIndex > catCounts.size() || respIndex < 1)
00125     {
00126       throw InvalidArgument("Invalid response index", "ItemRespCounts::AddResponse");
00127     }
00128 
00129     totalCount[0] += count; // total count
00130     totalCount[group] += count; // count for group
00131 
00132     catCounts(1, respIndex) += count; // total count
00133     catCounts(group+1, respIndex) += count; // count for group
00134   }
00135 
00136   /*!
00137     \brief
00138     Class constructor.
00139    
00140     \section function_args Function Parameters
00141    
00142     \param[in]  nitems    Total number of items.
00143     \param[in]  nlatentcat  Number of categories of discrete latent variable.
00144     \param[in]  ngroups   Number of examinee groups.
00145     \param[in]  minTheta  Minimum value of theta points for discrete latent 
00146         variable distribution.
00147     \param[in]  maxTheta  Maximum value of theta points for discrete latent 
00148         variable distribution.
00149     \param[in]  uniquePoints  If true then unique latent distribution points 
00150         are used for each examinee group.
00151    */
00152   SwigEtirmRun::SwigEtirmRun(int nitems, int nlatentcat, int ngroups, Real minTheta, Real maxTheta,
00153       bool uniquePoints) :
00154     numItems(nitems), numLatentCat(nlatentcat), numGroups(ngroups), examineeCounts(ngroups+1, 0.0),
00155         items(nitems), itemStats(nitems), minProc(nitems), latentDist(nlatentcat, ngroups,
00156             uniquePoints), rand_boot(0), base_rand_simulate(0), rand_simulate(0)
00157   {
00158     int i;
00159 
00160     // Set default points and weights for latent variable distribution to standard normal
00161     // for first group
00162     DiscreteNormalDist(nlatentcat, minTheta, maxTheta, latentDist.begin_points(1),
00163         latentDist.begin_weights(1));
00164 
00165     // Set points and weights for other groups equal to the points and weights for group 1
00166     for (i=2; i<=ngroups; ++i)
00167     {
00168       DiscreteLatentDist<Real>::weight_iterator w1 = latentDist.begin_weights(1);
00169       DiscreteLatentDist<Real>::weight_iterator w2 = latentDist.begin_weights(i);
00170       for (int j = nlatentcat; j--; ++w1, ++w2)
00171       {
00172         *w2 = *w1;
00173       }
00174 
00175       if (uniquePoints)
00176       {
00177         // initialize unique points for examinee group
00178         DiscreteLatentDist<Real>::point_iterator w1p = latentDist.begin_points(1);
00179         DiscreteLatentDist<Real>::point_iterator w2p = latentDist.begin_points(i);
00180         for (int j = nlatentcat; j--; ++w1p, ++w2p)
00181         {
00182           *w2p = *w1p;
00183         }
00184       }
00185     }
00186 
00187     /* initialize vectors of pointers to null */
00188     for (i=0; i<nitems; ++i)
00189     {
00190       items[i] = 0;
00191       itemStats[i] = 0;
00192       minProc[i] = 0;
00193     }
00194 
00195   }
00196 
00197   //! Releases memory allocated by constructor.
00198   SwigEtirmRun::~SwigEtirmRun()
00199   {
00200     int i;
00201 
00202     for (i=0; i<numItems; i++)
00203     {
00204       if (items[i])
00205       {
00206         items[i]->DeletePriors();
00207         delete items[i];
00208       }
00209 
00210       if (itemStats[i])
00211         delete itemStats[i];
00212       if (minProc[i])
00213         delete minProc[i];
00214     }
00215 
00216     int n = examinees.size();
00217     for (i=0; i<n; ++i)
00218     {
00219       delete examinees[i];
00220     }
00221 
00222     delete rand_boot;
00223     delete base_rand_simulate;
00224     delete rand_simulate;
00225   }
00226 
00227   // Check that data for examinees exist
00228   void SwigEtirmRun::CheckExaminees(const char *funcname)
00229   {
00230     if ((gEtirmRun->examinees).size() == 0)
00231     {
00232       throw RuntimeError("Error: No examinee data", funcname);
00233     }
00234   }
00235 
00236   // Check that examinee number is valid
00237   void SwigEtirmRun::CheckExamineeNumber(int examno, const char *funcname)
00238   {
00239     if ( (examno < 1) || ( examno > (gEtirmRun->examinees).size() ) )
00240     {
00241       char errstr[50];
00242       std::sprintf(errstr, "Invalid examinee number: %d", examno);
00243       gEtirmRun->returnString = errstr;
00244       throw RuntimeError((gEtirmRun->returnString).c_str(), funcname);
00245     }
00246   }
00247 
00248   // Check that item number is valid
00249   void SwigEtirmRun::CheckItemNumber(int itemno, const char *funcname)
00250   {
00251     if (itemno < 1 || itemno >(gEtirmRun->numItems) ) // Syntax edited, ww, 2-24-2008.
00252     {
00253       char errstr[50];
00254       std::sprintf(errstr, "Invalid item number: %d", itemno);
00255       gEtirmRun->returnString = errstr;
00256       throw RuntimeError((gEtirmRun->returnString).c_str(), funcname);
00257     }
00258   }
00259 
00260   // Check that group number is valid
00261   //  group   Value to check.
00262   //  funcname  Name of calling function (used in error message)
00263   void SwigEtirmRun::CheckGroup(int group, const char *funcname)
00264   {
00265     if (group < 1 || group >(gEtirmRun->numGroups) ) // Syntax edited, ww, 2-24-2008
00266     {
00267       char errstr[50];
00268       std::sprintf(errstr, "Invalid examinee group: %d", group);
00269       gEtirmRun->returnString = errstr;
00270       throw RuntimeError((gEtirmRun->returnString).c_str(), funcname);
00271     }
00272   }
00273 
00274   /*! 
00275     \brief
00276     Tests whether item parameter index is valid for the item.
00277    
00278     \section function_args Function Parameters
00279     
00280     \param[in]  *item   Pointer to item object for which index is checked.
00281     \param[in]  index   Zero-offset index of item parameter.
00282     \param[in]  *funcname pointer to name of calling function (used in error message).
00283    */
00284   void CheckItemParam(item_type *item, int index, const char *funcname)
00285   {
00286     if (item->NumParameters() <= index || index < 0)
00287     {
00288       char errstr[100];
00289       std::sprintf(errstr, "Invalid item parameter index for item %d: %d", item->Index()+1, index);
00290       gEtirmRun->returnString = errstr;
00291       throw RuntimeError((gEtirmRun->returnString).c_str(), funcname);
00292     }
00293   }
00294 
00295   /*!
00296     \brief
00297     Create a prior distribution object and return a pointer to it.
00298    
00299     \section function_args Function Parameters
00300 
00301     \param[in]  pstr  Type of prior distribution, valued as ("none", "normal", "lognormal", "beta").
00302     \param[in]  priorparam  Parameters of prior distribution.
00303     \param[in]  funcname  Name of calling function (used in error messages)
00304    */
00305   ItemParamPrior *CreatePrior(const std::string &pstr, const double_vector &priorparam,
00306       const char *funcname)
00307   {
00308     const char *err_message = "Invalid number of prior parameters";
00309 
00310     if (pstr.compare("none") == 0)
00311     {
00312       return 0;
00313     }
00314     else if (pstr.compare("normal") == 0)
00315     {
00316       if (priorparam.size() != 2)
00317         throw RuntimeError(err_message, funcname);
00318       return new ItemParamPriorNormal(priorparam[0], priorparam[1]);
00319     }
00320     else if (pstr.compare("lognormal") == 0)
00321     {
00322       if (priorparam.size() != 2)
00323         throw RuntimeError(err_message, funcname);
00324       return new ItemParamPriorLogNormal(priorparam[0], priorparam[1]);
00325     }
00326     else if (pstr.compare("beta") == 0)
00327     {
00328       if (priorparam.size() != 4)
00329         throw RuntimeError(err_message, funcname);
00330       return new ItemParamPriorBeta4(priorparam[0], priorparam[1], priorparam[2], priorparam[3]);
00331     }
00332     else
00333     {
00334       throw RuntimeError("Invalid prior type", funcname);
00335     }
00336     return 0;
00337   }
00338 
00339   /*!
00340     \brief
00341     Converts a response for an item into a character, where '0' represents the 
00342     first response, '1' represents the second response, etc.
00343    
00344     If the number of response categories for the item is greater than 10, then the 
00345     characters returned will be ascii characters greater than '9'. For example, a 
00346     ':' is return for a response in response category 11, since ':' is one greater
00347     than '9' in the ascii sequence.
00348 
00349     \section function_args Function Parameters
00350     
00351     \param[in]  r Item response to be converted.
00352     \param[in]  *item Pointer to item object.
00353    */
00354   char Resp2Char(Response r, const item_type *item)
00355   {
00356     const char zero = '0';
00357     Response np = item_type::NotPresentedResponse();
00358     char cr;
00359     if (r == np)
00360       cr = np - item->FirstResponse() + zero;
00361     else
00362       cr = item->ResponseIndex(r) + zero;
00363 
00364     return cr;
00365   }
00366 
00367   /****** Functions for which SWIG wrappers are generated ******/
00368 
00369   /* Member functions for estep class */
00370 
00371   /*!
00372     \brief
00373     Initialize estep object.
00374    
00375     \section function_args Function Parameters
00376    
00377     \param[in]  *itemno Pointer to list of item numbers to use for computing 
00378     examinee posteriors distribution in E-Step. If itemno = NUL, use all items (default).
00379    */
00380   estep::estep(int_vector *itemno)
00381   {
00382     CheckRunInit();
00383 
00384     if (itemno)
00385     {
00386       mItems = new ItemVector(ItemSubset(itemno,gEtirmRun->items,"new_estep"));
00387 
00388       mEStep = new estep_type(mItems->begin(), mItems->end(), gEtirmRun->latentDist);
00389     }
00390     else
00391     {
00392       mItems = 0;
00393       mEStep = new estep_type((gEtirmRun->items).begin(), (gEtirmRun->items).end(), gEtirmRun->latentDist);
00394     }
00395   }
00396 
00397   /*!
00398     \brief
00399     Release memory allocated in constructor.
00400    */
00401   estep::~estep()
00402   {
00403     if (mItems)
00404       delete mItems;
00405     delete mEStep;
00406   }
00407 
00408   /*!
00409     \brief
00410     Calls mEStep->DoEStep to perform E-step.
00411    
00412     Returns marginal loglikelihood of examinees' responses (sum over examinees of the 
00413     marginal loglikelihood of an examinee's responses) plus sum of prior likelihoods 
00414     over all item parameters.  This is the value of the marginal posterior density that 
00415     the EM algorithm is maximizing at the values of the item parameters computed in the 
00416     last M-step.
00417    
00418     \section function_args Function Parameters
00419    
00420     \param[in]  compute_post  Flag: If compute_post == TRUE, then compute posterior 
00421     distributions for all examinees. If compute_post == FALSE, then use previously 
00422     stored posteriors for examinees. (Default: TRUE).
00423    
00424     \param[in]  store_post  Flag: If store_post == TRUE, then store the posterior 
00425     distribution computed for each examinee. These posterior distributions are 
00426     stored as part of the examinee objects.
00427     (Default: FALSE).
00428    
00429     \param[in]  *estep_items  Pointer to list of items for which n and r are updated. If a 
00430     null pointer is passed then n arnd r are updated for all items used in the E-step 
00431     to compute examinee posterior distributions.
00432    */
00433   double estep::compute(bool compute_post, bool store_post, int_vector *estep_items) // compute_post and store_post retyped as "bool", ww, 2-24-2008.
00434   {
00435     const char *fname = "estep_compute";
00436     CheckRunInit();
00437     gEtirmRun->CheckExaminees(fname);
00438 
00439     if (estep_items)
00440     {
00441       if (estep_items->size() > 0)
00442       {
00443         ItemVector itemsub = ItemSubset(estep_items, gEtirmRun->items, fname);
00444         return mEStep->DoEStep((gEtirmRun->examinees).begin(), (gEtirmRun->examinees).end(), itemsub.begin(), itemsub.end(), compute_post, store_post);
00445       }
00446       else // do not update n and r for any items
00447       {
00448         return mEStep->DoEStep((gEtirmRun->examinees).begin(), (gEtirmRun->examinees).end(), (gEtirmRun->items).begin(), (gEtirmRun->items).begin(), compute_post, store_post);
00449       }
00450     }
00451     else
00452     {
00453       return mEStep->DoEStep((gEtirmRun->examinees).begin(), (gEtirmRun->examinees).end(), compute_post, store_post);
00454     }
00455   }
00456 
00457   /*!
00458     \brief
00459     Assigns missing response code to identify examinees who did not respond to an item.
00460    */
00461   void set_missing_resp(char nr)
00462   {
00463     if (gEtirmRun)
00464     {
00465       throw RuntimeError("The not presented response can only be set before any items are initialized", 0);
00466     }
00467     Item<Real>::SetNotPresentedResponse(nr);
00468   }
00469 
00470   /*!
00471     \brief
00472     Returns the number of items.
00473    */
00474   int num_items()
00475   {
00476     CheckRunInit();
00477 
00478     return gEtirmRun->numItems;
00479   }
00480 
00481   /*!
00482     \brief
00483     Returns number of categories of the discrete theta distribution.
00484    */
00485   int num_latent_dist_points()
00486   {
00487     CheckRunInit();
00488 
00489     return gEtirmRun->numLatentCat;
00490   }
00491 
00492   /*!
00493     \brief
00494     Returns number of examinee groups.
00495    */
00496   int num_groups()
00497   {
00498     CheckRunInit();
00499 
00500     return gEtirmRun->numGroups;
00501   }
00502 
00503   /*!
00504     \brief
00505     Returns number of examinees.
00506    */
00507   int num_examinees()
00508   {
00509     CheckRunInit();
00510 
00511     return (gEtirmRun->examinees).size();
00512   }
00513 
00514   /*!
00515     \brief
00516     Returns the name of model used for an item.
00517    
00518     \section function_args Function Parameters
00519    
00520     \param[in]  itemno Item number (1-offset).
00521    */
00522   const char * item_get_model(int itemno)
00523   {
00524 
00525     CheckRunInit();
00526     std::string &modelName = gEtirmRun->returnString;
00527     gEtirmRun->CheckItemNumber(itemno, "item_get_model");
00528 
00529     item_type *item = (gEtirmRun->items)[itemno-1];
00530     modelName = item->ModelName();
00531 
00532     return modelName.c_str();
00533   }
00534 
00535   /*!
00536     \brief
00537     Assigns a value to one item parameter of an item.
00538    
00539     \section function_args Function Parameters
00540    
00541     \param[in] paramno  1-offset index of parameter in parameter vector for item.
00542     \param[in] itemno   Item number (1-offset).
00543     \param[in] paramvalue Value parameter is set to.
00544    */
00545   void item_set_param(int paramno, int itemno, double paramvalue)
00546   {
00547     const char *fname = "item_set_param";
00548     CheckRunInit();
00549     int index = paramno - 1;
00550 
00551     gEtirmRun->CheckItemNumber(itemno, fname);
00552     item_type *item = (gEtirmRun->items)[itemno-1];
00553     CheckItemParam(item, index, fname);
00554 
00555     /* Check that value of parameter has nonzero prior density */
00556     item_type::prior_iterator pri = item->PriorsIterator() + index;
00557     if (*pri && (*pri)->ZeroDensity(paramvalue))
00558     {
00559       char merr[100];
00560       std::sprintf(merr, "Parameter specified for item %d has zero prior density", itemno);
00561       gEtirmRun->returnString = merr;
00562       throw RuntimeError((gEtirmRun->returnString).c_str(), fname);
00563     }
00564 
00565     item_type::param_iterator pv = item->ParametersIterator();
00566 
00567     pv[index] = paramvalue;
00568   }
00569 
00570   /*!
00571     \brief
00572     Assigns values to all item parameters of an item.
00573    
00574     \section function_args Function Parameters
00575    
00576     \param[in]  itemno  Item number (1-offset).
00577     \param[in]  *params  Pointer to params vector containing the values to set the 
00578         parameters to.
00579    
00580     Note: The order of the parameters in the params vector is: 
00581     a (if there is an a parameter), one or more b's, and
00582     c (if there is a c parameter).
00583    */
00584   void item_set_params(int itemno, double_vector *params)
00585   {
00586     const char *fname = "item_set_params";
00587     CheckRunInit();
00588     gEtirmRun->CheckItemNumber(itemno, fname);
00589 
00590     item_type *item = (gEtirmRun->items)[itemno-1];
00591 
00592     // Assign new parameters
00593     item_type::param_iterator pv = item->ParametersIterator();
00594     double_vector::iterator iv = params->begin();
00595     int n;
00596     for (n = item->NumParameters(); n--; ++pv, ++iv)
00597     {
00598       *pv = *iv;
00599     }
00600 
00601     /* Check that values of all parameters have nonzero prior density */
00602     iv = params->begin();
00603     item_type::prior_iterator pri = item->PriorsIterator();
00604     for (n = item->NumParameters(); n--; ++pri, ++iv)
00605     {
00606       if (*pri && (*pri)->ZeroDensity(*iv))
00607       {
00608         char merr[100];
00609         std::sprintf(merr, "Parameter specified for item %d has zero prior density", itemno);
00610         throw InvalidArgument(merr, fname);
00611       }
00612     }
00613   }
00614 
00615   /*!
00616     \brief
00617     Assigns values to all fixed and estimated item parameters of an item.
00618    
00619     \section function_args Function Parameters
00620    
00621     \param[in]  itemno  Item number (1-offset).
00622     \param[in]  *params  Pointer to params vector containing the values to set the 
00623         parameters to.
00624    
00625     Note: The order of the parameters in the params vector is: 
00626     a (if there is an a parameter), one or more b's, and
00627     c (if there is a c parameter).
00628    */
00629   void item_set_all_params(int itemno, double_vector *params)
00630   {
00631     const char *fname = "item_set_all_params";
00632     CheckRunInit();
00633     gEtirmRun->CheckItemNumber(itemno, fname);
00634 
00635     item_type *item = (gEtirmRun->items)[itemno-1];
00636 
00637     // Assign new fixed and estimated parameters
00638     item->SetAllParameters(*params);
00639 
00640     /* Check that values of estimated parameters all have nonzero prior density */
00641     item_type::param_iterator iv = item->ParametersIterator();
00642     item_type::prior_iterator pri = item->PriorsIterator();
00643     for (int n = item->NumParameters(); n--; ++pri, ++iv)
00644     {
00645       if (*pri && (*pri)->ZeroDensity(*iv))
00646       {
00647         char merr[100];
00648         std::sprintf(merr, "Parameter specified for item %d has zero prior density", itemno);
00649         gEtirmRun->returnString = merr;
00650         throw InvalidArgument((gEtirmRun->returnString).c_str(), fname);
00651       }
00652     }
00653   }
00654 
00655   /*!
00656     \brief
00657     Returns value of one item parameter of an item.
00658    
00659     \section function_args Function Parameters
00660     
00661     \param[in]  paramno  1-offset index of the parameter in the item's parameter vector.
00662     \param[in]  itemno  Item number (1-offset).
00663    
00664     Note: The order of the parameters in the params vector is: 
00665     a (if there is an a parameter), one or more b's, and
00666     c (if there is a c parameter).
00667    */
00668   double item_get_param(int paramno, int itemno)
00669   {
00670     const char *fname = "item_get_param";
00671     CheckRunInit();
00672     int index = paramno - 1;
00673 
00674     gEtirmRun->CheckItemNumber(itemno, fname);
00675     item_type *item = (gEtirmRun->items)[itemno-1];
00676     CheckItemParam(item, index, fname);
00677 
00678     item_type::param_iterator pv = item->ParametersIterator();
00679 
00680     return pv[index];
00681   }
00682 
00683   /*!
00684     \brief
00685     Returns vector of all estimated item parameters values of an item.
00686    
00687     \section function_args Function Parameters
00688    
00689     \param[in]  itemno  Item number (1-offset).
00690    
00691     Note: The order of the parameters in the params vector is: 
00692     a (if there is an a parameter), one or more b's, and
00693     c (if there is a c parameter).
00694    */
00695   double_vector *item_get_params(int itemno)
00696   {
00697     CheckRunInit();
00698     gEtirmRun->CheckItemNumber(itemno, "item_get_params");
00699 
00700     item_type *item = (gEtirmRun->items)[itemno-1];
00701 
00702     int n = item->NumParameters();
00703     double_vector *params = new double_vector(n);
00704 
00705     item_type::param_iterator pv = item->ParametersIterator();
00706     double_vector::iterator iv = params->begin();
00707     for (; n--; ++pv, ++iv)
00708     {
00709       *iv = *pv;
00710     }
00711 
00712     return params;
00713   }
00714 
00715   /*!
00716     \brief
00717     Returns vector of all fixed and estimated item parameters values of an item.
00718    
00719     \section function_args Function Parameters
00720    
00721     \param[in]  itemno  Item number (1-offset).
00722    
00723     Note: The order of the parameters in the params vector is: 
00724     a (if there is an a parameter), one or more b's, and
00725     c (if there is a c parameter).
00726    */
00727   double_vector *item_get_all_params(int itemno)
00728   {
00729     CheckRunInit();
00730     gEtirmRun->CheckItemNumber(itemno, "item_get_all_params");
00731 
00732     item_type *item = (gEtirmRun->items)[itemno-1];
00733 
00734     RealVector allparam = item->GetAllParameters();
00735     int n = allparam.size();
00736     double_vector *params = new double_vector(n);
00737 
00738     RealVector::iterator pv = allparam.begin();
00739     double_vector::iterator iv = params->begin();
00740     for (; n--; ++pv, ++iv)
00741     {
00742       *iv = *pv;
00743     }
00744 
00745     return params;
00746   }
00747 
00748   /*!
00749     \brief
00750     Returns the number of parameters of an item.
00751 
00752     \section function_args Function Parameters
00753    
00754     \param[in]  itemno  Item number (1-offset).
00755    */
00756   int item_num_params(int itemno)
00757   {
00758     CheckRunInit();
00759     gEtirmRun->CheckItemNumber(itemno, "item_num_params");
00760 
00761     item_type *item = (gEtirmRun->items)[itemno-1];
00762 
00763     return item->NumParameters();
00764   }
00765 
00766   /*!
00767     \brief
00768     Returns the number of response categories of an item.
00769 
00770     \section function_args Function Parameters
00771    
00772     \param[in]  itemno  Item number (1-offset).
00773    */
00774   int item_num_resp_cat(int itemno)
00775   {
00776     CheckRunInit();
00777     gEtirmRun->CheckItemNumber(itemno, "item_num_resp_cat");
00778 
00779     item_type *item = (gEtirmRun->items)[itemno-1];
00780 
00781     return item->NumRespCat();
00782   }
00783 
00784   /*!
00785     \brief
00786     Assigns prior distribution parameters for one item parameter.
00787 
00788     \section function_args Function Parameters
00789    
00790     \param[in]  paramno 1-offset index of parameter in parameter vector for item.
00791     \param[in]  itemno  Number of item for which prior is set (1-offset).
00792     \param[in]  *priortype Pointer to type of prior distribution ("normal", "lognormal", "beta", "none").
00793     \param[in]  *dlist Pointer to vector of prior distribution parameters.
00794    */
00795   void item_set_prior(int paramno, int itemno, char *priortype, double_vector *dlist)
00796   {
00797     const char *funcname = "item_set_prior";
00798     CheckRunInit();
00799     int index = paramno - 1;
00800 
00801     gEtirmRun->CheckItemNumber(itemno, funcname);
00802     item_type *item = (gEtirmRun->items)[itemno-1];
00803     CheckItemParam(item, index, funcname);
00804 
00805     item_type::prior_iterator pv = item->PriorsIterator() + index;
00806 
00807     if (*pv)
00808       delete *pv;
00809 
00810     std::string pstr(priortype);
00811     *pv = CreatePrior(pstr, *dlist, funcname);
00812   }
00813 
00814   /*!
00815     \brief
00816     Returns type of prior distribution ("normal", "lognormal", "beta", "none")
00817     for one item parameter.
00818 
00819     \section function_args Function Parameters
00820    
00821     \param[in]  paramno 1-offset index of parameter in parameter vector for item.
00822     \param[in]  itemno  Number of item for which prior is returned (1-offset).
00823    */
00824   const char *item_get_prior_type(int paramno, int itemno)
00825   {
00826     const char *fname = "item_get_prior_type";
00827     CheckRunInit();
00828     std::string &priorName = gEtirmRun->returnString;
00829     int index = paramno - 1;
00830 
00831     gEtirmRun->CheckItemNumber(itemno, fname);
00832     item_type *item = (gEtirmRun->items)[itemno-1];
00833     CheckItemParam(item, index, fname);
00834 
00835     item_type::prior_iterator pv = item->PriorsIterator() + index;
00836 
00837     if (*pv != 0)
00838     {
00839       priorName = (*pv)->DistributionName();
00840     }
00841     else
00842     {
00843       priorName = "none";
00844     }
00845 
00846     return priorName.c_str();
00847   }
00848 
00849   /*!
00850     \brief
00851     Returns vector of prior distribution parameters for one item parameter.
00852 
00853     \section function_args Function Parameters
00854    
00855     \param[in]  paramno 1-offset index of parameter in parameter vector for item.
00856     \param[in]  itemno  Number of item for which prior is returned (1-offset).
00857    */
00858   double_vector *item_get_prior_param(int paramno, int itemno)
00859   {
00860     const char *fname = "item_get_prior_param";
00861     CheckRunInit();
00862     int index = paramno - 1;
00863 
00864     gEtirmRun->CheckItemNumber(itemno, fname);
00865     item_type *item = (gEtirmRun->items)[itemno-1];
00866     CheckItemParam(item, index, fname);
00867 
00868     item_type::prior_iterator pv = item->PriorsIterator() + index;
00869 
00870     double_vector *v;
00871     if (*pv != 0)
00872     {
00873       int n = (*pv)->NumParameters();
00874 
00875       v = new double_vector(n);
00876 
00877       *v = (*pv)->GetParameters();
00878     }
00879     else
00880     {
00881       v = new double_vector();
00882     }
00883 
00884     return v;
00885   }
00886 
00887   /*!
00888     \brief
00889     Returns vector of response counts in each response category of an item.
00890    
00891     \section function_args Function Parameters
00892    
00893     \param[in]  itemno  Number of item for which response counts are returned (1-offset).
00894     \param[in]  group Group to return counts for (1-offset). Specify group = 0 to return 
00895         counts across all groups.
00896    */
00897   double_vector *item_cat_counts(int itemno, int group)
00898   {
00899     const char *fname = "item_cat_counts";
00900     CheckRunInit();
00901 
00902     gEtirmRun->CheckItemNumber(itemno, fname);
00903     if (group != 0)
00904       gEtirmRun->CheckGroup(group, "item_resp_count");
00905 
00906     ItemRespCounts *stats = (gEtirmRun->itemStats)[itemno-1];
00907 
00908     double_vector *v = new double_vector(stats->CategoryCounts(group));
00909 
00910     return v;
00911   }
00912 
00913   /*!
00914     \brief
00915     Returns the number of examinees responding to an item.
00916    
00917     \section function_args Function Parameters
00918    
00919     \param[in]  itemno  Number of item for which response counts are returned (1-offset).
00920     \param[in]  group Group to return counts for (1-offset). Specify group = 0 to return 
00921         count across all groups.
00922    */
00923   double item_resp_count(int itemno, int group)
00924   {
00925     CheckRunInit();
00926 
00927     gEtirmRun->CheckItemNumber(itemno, "item_resp_count");
00928     if (group != 0)
00929       gEtirmRun->CheckGroup(group, "item_resp_count");
00930 
00931     return (gEtirmRun->itemStats)[itemno-1]->RespCount(group);
00932   }
00933   /*!
00934     \brief
00935     Transforms the parameter estimates of an item to a different latent variable scale.
00936    
00937     Returns zero if parameters are successfully scaled, or returns nonzero if
00938     scaling would result in an invalid parameter value.   
00939 
00940     \section function_args Function Parameters
00941    
00942     \param[in]  itemno  Number of item for which to transform parameters (1-offset).
00943     \param[in]  slope  Slope of scale transformation to apply to item parameters.
00944     \param[in]  intercept Intercept of scale transformation to apply to item parameters.
00945     \param[in]  ignorePriorError  If true then do not report an error if transformed parameter
00946         has zero density in prior used for that parameter.
00947    */
00948   int item_scale_params(int itemno, double slope, double intercept, bool ignorePriorError) 
00949   { // Retyped ignorePriorErro from "int" to "bool", ww, 2-24-2008.
00950     CheckRunInit();
00951 
00952     gEtirmRun->CheckItemNumber(itemno, "item_scale_params");
00953     item_type *item = (gEtirmRun->items)[itemno-1];
00954 
00955     return item->ScaleParameters(slope, intercept, ignorePriorError);
00956   }
00957 
00958   /*!
00959     \brief
00960     Returns the probability that an examinee with a particular theta value will give a 
00961     particular response to a particular item.
00962    
00963     \section function_args Function Parameters
00964    
00965     \param[in]  itemno  Number (1-based) of item for which response probability is returned.
00966     \param[in]  response  Integer representing response, where a response in the first
00967         response category is 0, a response in the second response category is 1, etc.
00968     \param[in]  theta Value of latent variable for which response probability is returned.
00969    */
00970   double item_prob_resp(int itemno, int response, double theta)
00971   {
00972     CheckRunInit();
00973     gEtirmRun->CheckItemNumber(itemno, "item_prob_resp");
00974 
00975     item_type *item = (gEtirmRun->items)[itemno-1];
00976 
00977     return item->ProbResp(item->IndexResponse(response), theta);
00978   }
00979 
00980   /*!
00981     \brief
00982     Returns a vector of values of the test characteristic curve, given a vector of theta values and
00983     a selection of items. 
00984    
00985     It is assumed for each item that the lowest response category corresponds to a score of 0, the
00986     second response category corresponds to a score of 1, etc.
00987 
00988     \section function_args Function Parameters
00989    
00990     \param[in]  *thetas Pointer to vector of theta values.
00991     \param[in]  *ilist2 Pointer to vector of item sequence numbers (1-based).
00992    */
00993   double_vector *test_characteristic_curve(double_vector *thetas, int_vector *ilist2)
00994   {
00995     CheckRunInit();
00996 
00997     double_vector tcc(thetas->size(), 0.0);
00998 
00999     // Vector to hold response probabilities for an item.
01000     double_vector probs;
01001 
01002     ItemVector *sitems;
01003     if (ilist2)
01004     {
01005       sitems = new ItemVector(ItemSubset(ilist2, gEtirmRun->items, "test_characteristic_curve"));
01006     }
01007     else
01008     {
01009       sitems = &(gEtirmRun->items);
01010     }
01011 
01012     // loop over items
01013     ItemVector::iterator ii = sitems->begin();
01014     for (int i = sitems->size(); i--; ++ii)
01015     {
01016       int ncat = (*ii)->NumRespCat();
01017       probs.newsize(ncat);
01018 
01019       double_vector::iterator icc = tcc.begin();
01020       double_vector::iterator it = thetas->begin();
01021       for (int j = tcc.size(); j--; ++icc, ++it) // loop over thetas
01022       {
01023         (*ii)->ProbRespAll(*it, probs.begin());
01024 
01025         // first response category corresponds to 0, second response category
01026         // corresponds to 1, etc.
01027         double dresp = 1.0; // Start with response 1, 0 is skipped
01028         double sum = 0.0;
01029         double_vector::iterator ip = probs.begin()+1;
01030         for (int k = ncat-1; k--; ++ip, ++dresp)
01031         {
01032           sum += dresp * *ip;
01033         }
01034 
01035         // Add expected score for item to TCC
01036         *icc += sum;
01037       }
01038     }
01039 
01040     if (ilist2)
01041       delete sitems;
01042 
01043     return new double_vector(tcc);
01044   }
01045 
01046   /*!
01047     \brief
01048     Assigns quadrature point values to each discrete category of the discrete latent variable distribution.
01049 
01050     \section function_args Function Parameters
01051    
01052     \param[in]  *dlist Pointer to vector of quadrature points of the latent variable distribution.
01053     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01054    */
01055   void dist_set_points(double_vector *dlist, int group)
01056   {
01057     CheckRunInit();
01058     gEtirmRun->CheckGroup(group, "dist_set_points");
01059 
01060     int n = dlist->size();
01061     if (n != (gEtirmRun->latentDist).size())
01062     {
01063       throw RuntimeError("Number of points does not match number of categories in latent distribution",
01064           "dist_set_points");
01065     }
01066 
01067     DiscreteLatentDist<Real>::point_iterator ip = (gEtirmRun->latentDist).begin_points(group);
01068 
01069     double_vector::iterator id = dlist->begin();
01070     for (; n--; ++ip, ++id)
01071     {
01072       *ip = *id;
01073     }
01074   }
01075 
01076   /*!
01077     \brief
01078     Assigns a quadrature point value to one discrete category of the discrete latent variable distribution.
01079 
01080     \section function_args Function Parameters
01081    
01082     \param[in]  index Index of latent variable category (1, 2, ..., number of categories).
01083     \param[in]  p Value to assign to point.
01084     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01085    */
01086   void dist_set_point(int index, double p, int group)
01087   {
01088     CheckRunInit();
01089     gEtirmRun->CheckGroup(group, "dist_set_point");
01090 
01091     if (index < 1 || index> (gEtirmRun->latentDist).size())
01092     {
01093       throw RuntimeError("Invalid category of latent variable distribution","dist_set_point");
01094     }
01095 
01096     DiscreteLatentDist<Real>::point_iterator ip = (gEtirmRun->latentDist).begin_points(group);
01097 
01098     ip[index-1] = p;
01099   }
01100 
01101   /*!
01102     \brief
01103     Returns vector of quadrature point values of the discrete latent variable distribution.
01104 
01105     \section function_args Function Parameters
01106    
01107     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01108    */
01109   double_vector *dist_get_points(int group)
01110   {
01111     CheckRunInit();
01112     gEtirmRun->CheckGroup(group, "dist_get_points");
01113 
01114     DiscreteLatentDist<Real>::point_iterator ip = (gEtirmRun->latentDist).begin_points(group);
01115 
01116     int n = (gEtirmRun->latentDist).size();
01117     double_vector *outv = new double_vector(n);
01118     double_vector::iterator id = outv->begin();
01119     for (; n--; ++ip, ++id)
01120     {
01121       *id = *ip;
01122     }
01123 
01124     return outv;
01125   }
01126 
01127   /*!
01128     \brief
01129     Returns the quadrature point value of one discrete category of the discrete latent variable distribution.
01130 
01131     \section function_args Function Parameters
01132    
01133     \param[in]  index Index of latent variable category (1, 2, ..., number of categories).
01134     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01135    */
01136   double dist_get_point(int index, int group)
01137   {
01138     CheckRunInit();
01139     gEtirmRun->CheckGroup(group, "dist_get_point");
01140 
01141     if (index < 1 || index> (gEtirmRun->latentDist).size())
01142     {
01143       throw RuntimeError("Invalid category of latent variable distribution","dist_get_point");
01144     }
01145 
01146     DiscreteLatentDist<Real>::point_iterator ip = (gEtirmRun->latentDist).begin_points(group);
01147 
01148     return ip[index-1];
01149   }
01150 
01151   /*!
01152     \brief
01153     Assigns quadrature weights to the quadrature points of the latent variable distribution.
01154 
01155     \section function_args Function Parameters
01156    
01157     \param[in]  *dlist Pointer to vector of quadrature weights of the latent variable distribution.
01158     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01159    */
01160   void dist_set_probs(double_vector *dlist, int group)
01161   {
01162     CheckRunInit();
01163     gEtirmRun->CheckGroup(group, "dist_set_probs");
01164 
01165     int n = dlist->size();
01166     if (n != (gEtirmRun->latentDist).size())
01167     {
01168       throw RuntimeError("Number of probabilities does not match number of categories in latent distribution",
01169           "dist_set_probs");
01170     }
01171 
01172     // assign probabilities
01173     DiscreteLatentDist<Real>::weight_iterator ip = (gEtirmRun->latentDist).begin_weights(group);
01174     double_vector::iterator id = dlist->begin();
01175     Real sum = 0.0;
01176     for (; n--; ++ip, ++id)
01177     {
01178       *ip = *id;
01179       sum += *ip;
01180     }
01181 
01182     // standardize probabilities to they sum to 1
01183     ip = (gEtirmRun->latentDist).begin_weights(group);
01184     for (n = dlist->size(); n--; ++ip)
01185     {
01186       *ip /= sum;
01187     }
01188   }
01189 
01190   /*!
01191     \brief
01192     Assigns the quadrature weight to one discrete category of the discrete latent variable distribution.
01193 
01194     \section function_args Function Parameters
01195    
01196     \param[in]  index Index of latent variable category (1, 2, ..., number of categories).
01197     \param[in]  w Value to assign to weight.
01198     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01199    */
01200   void dist_set_prob(int index, double w, int group)
01201   {
01202     CheckRunInit();
01203     gEtirmRun->CheckGroup(group, "dist_set_prob");
01204 
01205     if (index < 1 || index> (gEtirmRun->latentDist).size())
01206     {
01207       throw RuntimeError("Invalid category of latent variable distribution","dist_set_prob");
01208     }
01209 
01210     DiscreteLatentDist<Real>::weight_iterator ip = (gEtirmRun->latentDist).begin_weights(group);
01211 
01212     ip[index-1] = w;
01213   }
01214 
01215   /*!
01216     \brief
01217     Returns vector of quadrature weights of the latent variable distribution for one group of
01218     examinees.
01219 
01220     \section function_args Function Parameters
01221    
01222     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01223    */
01224   double_vector *dist_get_probs(int group)
01225   {
01226     CheckRunInit();
01227     gEtirmRun->CheckGroup(group, "dist_get_probs");
01228 
01229     DiscreteLatentDist<Real>::weight_iterator ip = (gEtirmRun->latentDist).begin_weights(group);
01230 
01231     int n = (gEtirmRun->latentDist).size();
01232     double_vector *outv = new double_vector(n);
01233     double_vector::iterator id = outv->begin();
01234     for (; n--; ++ip, ++id)
01235     {
01236       *id = *ip;
01237     }
01238 
01239     return outv;
01240 
01241   }
01242 
01243   /*!
01244     \brief
01245     Returns the quadrature weight of one discrete category of the latent variable 
01246     distribution for one group of examinees.
01247 
01248     \section function_args Function Parameters
01249    
01250     \param[in]  index Index of latent variable category (1, 2, ..., number of categories).
01251     \param[in]  group Group to use (1, 2, ..., number of groups), default = 1.
01252    */
01253   double dist_get_prob(int index, int group)
01254   {
01255     CheckRunInit();
01256     gEtirmRun->CheckGroup(group, "dist_get_prob");
01257 
01258     if (index < 1 || index> (gEtirmRun->latentDist).size())
01259     {
01260       throw RuntimeError("Invalid category of latent variable distribution","dist_get_prob");
01261     }
01262 
01263     DiscreteLatentDist<Real>::weight_iterator ip = (gEtirmRun->latentDist).begin_weights(group);
01264 
01265     return ip[index-1];
01266   }
01267 
01268   /*!
01269     \brief
01270     Transforms the quadrature points of latent variable distribution to a new scale.
01271 
01272     \section function_args Function Parameters
01273    
01274     \param[in]  slope Slope parameter of linear scale transformation.
01275     \param[in]  intercept Intercept parameter of linear scale transformation.
01276    */
01277   void dist_transform(double slope, double intercept)
01278   {
01279     CheckRunInit();
01280 
01281     (gEtirmRun->latentDist).Transform(slope, intercept);
01282   }
01283 
01284   /*!
01285     \brief
01286     Scales to the quadrature points of latent variable distribution to yield a 
01287     specfic mean and standard deviation in one group.
01288 
01289     \section function_args Function Parameters
01290    
01291     \param[in]  mean  Mean of reference group after scaling the latent distribution.
01292     \param[in]  sd  Standard deviation of reference group after scaling the latent distribution.
01293     \param[in]  group Group to use as reference group (1, 2, ..., number of groups).
01294    */
01295   double_vector *dist_scale(double mean, double sd, int group)
01296   {
01297     CheckRunInit();
01298     gEtirmRun->CheckGroup(group, "dist_scale");
01299 
01300     double slope, intercept;
01301     (gEtirmRun->latentDist).Scale(mean, sd, group, slope, intercept);
01302 
01303     double_vector *outv = new double_vector(2);
01304 
01305     (*outv)[0] = slope;
01306     (*outv)[1] = intercept;
01307 
01308     return outv;
01309   }
01310 
01311   /*!
01312     \brief
01313     Returns a vector with the mean and standard deviation of the latent variable distribution 
01314     for a selected group of examinees.
01315 
01316     \section function_args Function Parameters
01317    
01318     \param[in]  group Group to use as reference group (1, 2, ..., number of groups).
01319    */
01320   double_vector *dist_mean_sd(int group)
01321   {
01322     CheckRunInit();
01323     gEtirmRun->CheckGroup(group, "dist_mean_sd");
01324 
01325     double mean, sd;
01326     (gEtirmRun->latentDist).MeanSD(group, mean, sd);
01327 
01328     double_vector *outv = new double_vector(2);
01329 
01330     (*outv)[0] = mean;
01331     (*outv)[1] = sd;
01332 
01333     return outv;
01334   }
01335 
01336   /*!
01337     \brief
01338     Returns 1 if unique sets of quadrature points are used for two or more groups of 
01339     examinees, or returns 0 otherwise.
01340    */
01341   int dist_unique_points()
01342   {
01343     CheckRunInit();
01344 
01345     return ((gEtirmRun->latentDist).NumGroupsUnique() > 1 && (gEtirmRun->latentDist).NumGroups() > 1);
01346   }
01347 
01348   /*!
01349     \brief
01350     Returns a vector of probabilities for a discrete distribution to approximate a normal distribution 
01351     over a set of equally spaced points.
01352 
01353     Note: The mean and s.d. parameters only effect the quadrature points themselves, so it does not
01354     matter which values are passed for the mean and s.d.
01355 
01356     \section function_args Function Parameters
01357    
01358     \param[in]  npoints   Number of discrete points in the latent distribution.
01359     \param[in]  minPoint  Minimum point of the discrete distribution (must be smaller than the mean).
01360     \param[in]  maxPoint  Maximum point of the discrete distribution (must be larger than the mean).
01361     \param[in]  mean  Mean of the normal distribution.
01362     \param[in]  sd  Standard deviation of the normal distribution.
01363    */
01364   double_vector *normal_dist_prob(int npoints, double minPoint, double maxPoint, double mean,
01365       double sd)
01366   {
01367     RealVector points(npoints);
01368     RealVector *prob = new RealVector(npoints);
01369 
01370     DiscreteNormalDist(npoints, minPoint, maxPoint, points.begin(), prob->begin(), mean, sd);
01371 
01372     return prob;
01373   }
01374 
01375   /*!
01376     \brief
01377     Returns a vector of quadrature points for a discrete distribution over a set of equally-spaced 
01378     points.
01379     \section function_args Function Parameters
01380    
01381     \param[in]  npoints   Number of discrete points in the latent distribution.
01382     \param[in]  minPoint  Minimum point of the discrete distribution (must be smaller than the mean).
01383     \param[in]  maxPoint  Maximum point of the discrete distribution (must be larger than the mean).
01384     \param[in]  mean  Mean of the normal distribution.
01385     \param[in]  sd  Standard deviation of the normal distribution.
01386    */
01387   double_vector *normal_dist_points(int npoints, double minPoint, double maxPoint, double mean,
01388       double sd)
01389   {
01390     RealVector prob(npoints);
01391     RealVector *points = new RealVector(npoints);
01392 
01393     // Probabilities do not matter so make up mean and sd
01394     DiscreteNormalDist(npoints, minPoint, maxPoint, points->begin(), prob.begin(), mean, sd);
01395 
01396     return points;
01397   }
01398   
01399   /*!
01400     \brief
01401     CalculateS M-step for a set of items.
01402 
01403     \section function_args Function Parameters
01404    
01405     \param[in]  ignore_max_iter Flag: If ignore_max_iter == TRUE, then exceeding the maximum number of 
01406         iterations in optimization procedure is NOT a fatal error; if ignore_max_iter == FALSE, then the
01407         exceeding the max_iter is treated as a fatal error (default = FALSE).
01408     \param[in]  *itemno  Pointer to vector of integers giving item numbers (1-offset)
01409        for which the M-step is calculated. If itemno is the null pointer, then all items are used
01410        (default = null).
01411    */
01412   int mstep_items(bool ignore_max_iter, int_vector *itemno)
01413   {  // Retyped ignore_max_iter from "int" to "bool", ww, 2-25-2008.
01414     CheckRunInit();
01415 
01416     if (itemno)
01417     {
01418       const char *fname = "mstep_items";
01419       ItemVector itemsub = ItemSubset(itemno, gEtirmRun->items, fname);
01420       UncminVector minsub = ItemSubset(itemno, gEtirmRun->minProc, fname);
01421       return MStepItems(minsub.begin(), itemsub.begin(), itemsub.end(), gEtirmRun->mstepMaxDiff,
01422           ignore_max_iter);
01423     }
01424     else
01425     {
01426       return MStepItems((gEtirmRun->minProc).begin(), (gEtirmRun->items).begin(), (gEtirmRun->items).end(), gEtirmRun->mstepMaxDiff, ignore_max_iter);
01427     }
01428   }
01429 
01430   /*!
01431     \brief
01432     Returns message from M-step minimization for one item.
01433 
01434     \section function_args Function Parameters
01435    
01436     \param[in]  itemno  Integer giving item number (1-offset).
01437    */
01438   int mstep_message(int itemno)
01439   {
01440     CheckRunInit();
01441     gEtirmRun->CheckItemNumber(itemno, "mstep_message");
01442 
01443     return ((gEtirmRun->minProc)[itemno-1])->GetMessage();
01444   }
01445 
01446   /*!
01447     \brief
01448     Assigns the maximum number of iterations permitted with optimization procedure
01449     in mstep_items for one item.
01450       
01451     \section function_args Function Parameters
01452    
01453     \param[in]  itemno  Integer giving item number (1-offset).
01454     \param[in]  maxiter  Maximum number of iterations for stepwise optimization.
01455    */
01456   void mstep_max_iter(int itemno, int maxiter)
01457   {
01458     CheckRunInit();
01459     gEtirmRun->CheckItemNumber(itemno, "mstep_max_iter");
01460 
01461     return ((gEtirmRun->minProc)[itemno-1])->SetMaxIter(maxiter);
01462   }
01463 
01464   /*!
01465     \brief
01466     Returns the maximum relative difference between parameter estimates in two
01467     successive EM iterations, as computed in last call to mstep_items.
01468    */
01469   double mstep_max_diff()
01470   {
01471     CheckRunInit();
01472 
01473     return gEtirmRun->mstepMaxDiff;
01474   }
01475 
01476   /*!
01477     \brief
01478     Executes M-step for the latent distribution in one group.
01479     
01480     Returns maximum relative difference between new and old probabilities.
01481       
01482     \section function_args Function Parameters
01483    
01484     \param[in]  *e  Pointer to not sure what(?!). To-Do: Find out what *e relates to! 
01485     \param[in]  group Number of examinee group (1, 2, ..., number of groups).
01486    */
01487   double mstep_dist(estep *e, int group)
01488   {
01489     CheckRunInit();
01490     gEtirmRun->CheckGroup(group, "mstep_dist");
01491 
01492     estep_type::ngroup_iterator i = (e->GetEStep())->GetNGroup(group);
01493     RealVector::size_type n = (e->GetEStep())->size();
01494     RealVector prob(i, i+n);
01495     return (gEtirmRun->latentDist).MStep(prob, group);
01496   }
01497 
01498   /*!
01499     \brief
01500     Add an examinee objec to the end of the examinee vector.
01501     
01502     Returns the examinee number corresponding to this examinee.
01503 
01504     \section function_args Function Parameters
01505   
01506     \param[in]  *responses  Pointer to vector of integer-formatted item responses. 
01507         A negative integer indicates the examinee did not respond to the item.
01508         The integers representing responses are zero-offset (A response in the 
01509         first response category is represented as zero).
01510     \param[in]  group   Integer from 1 to maximum number of examinee groups
01511         giving the group the examinee belongs to.
01512     \param[in]  count   Frequency given to response pattern (usually, count = 1).
01513    */
01514   int add_examinee(int_vector *responses, int group, double count)
01515   {
01516     const char *fname = "add_examinee";
01517     CheckRunInit();
01518     gEtirmRun->CheckGroup(group, fname);
01519 
01520     int len = responses->size();
01521 
01522     if (len != gEtirmRun->numItems)
01523     {
01524       throw RuntimeError("Invalid number of item responses", fname);
01525     }
01526 
01527     examinee_type *e = new examinee_type(len, group);
01528 
01529     ResponseVector r(len);
01530     ItemVector::iterator iitem = (gEtirmRun->items).begin();
01531     int_vector::iterator iir = responses->begin();
01532     ResponseVector::iterator ir = r.begin();
01533     ItemStatsVector::iterator is = (gEtirmRun->itemStats).begin();
01534     Response np = Item<Real>::NotPresentedResponse();
01535     for (; len--; ++iitem, ++iir, ++ir, ++is)
01536     {
01537       if (*iir < 0)
01538         *ir = np;
01539       else
01540       {
01541         *ir = (*iitem)->IndexResponse(*iir);
01542         if (!((*iitem)->ValidResponse(*ir)))
01543         {
01544           throw RuntimeError("Invalid item response", fname);
01545         }
01546         (*is)->AddResponse(*iir+1, count, group);
01547       }
01548     }
01549 
01550     e->SetResponses(r);
01551     e->SetCount(count);
01552 
01553     (gEtirmRun->examinees).push_back(e);
01554 
01555     (gEtirmRun->examineeCounts)[0] += count; // total count
01556     (gEtirmRun->examineeCounts)[group] += count; // group count
01557 
01558     return (gEtirmRun->examinees).size();
01559   }
01560 
01561   /*!
01562     \brief
01563     Returns pointer to an integer vector of examinee item responses to all items.
01564 
01565     A non-negative integer indicates an examinee response in the category 
01566     represented by the integer (0 = first response category, 1 = second response 
01567     category, etc.). A negative integer indicates the examinee did not respond to 
01568     the item.
01569    
01570     \section function_args Function Parameters
01571   
01572     \param[in]  examineeno  Number of examinee for whom item responses are returned.
01573    */
01574   int_vector *examinee_responses(int examineeno)
01575   {
01576     const char *fname = "examinee_responses";
01577     CheckRunInit();
01578     gEtirmRun->CheckExamineeNumber(examineeno, fname);
01579 
01580     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01581 
01582     if ((gEtirmRun->items).size() != examinee->NumItems())
01583     {
01584       throw RuntimeError("Number of examinee responses does not match number of items", fname);
01585     }
01586 
01587     // iterators to first and one past last response
01588     examinee_type::response_iterator first = examinee->responses_begin();
01589     examinee_type::response_iterator last = examinee->responses_end();
01590 
01591     int_vector *responses = new int_vector(examinee->NumItems());
01592     int_vector::iterator ir = responses->begin();
01593     ItemVector::iterator ii = (gEtirmRun->items).begin();
01594     Response np = Item<Real>::NotPresentedResponse();
01595     while (first != last)
01596     {
01597       if (*first == np)
01598         *ir = -1;
01599       else
01600         *ir = (*ii)->ResponseIndex(*first);
01601       ++ir;
01602       ++ii;
01603       ++first;
01604     }
01605 
01606     return responses;
01607   }
01608 
01609   /*!
01610     \brief
01611     Returns string containing (character) examinee responses to all items.
01612     
01613     A response in the first response category is '0', a response in the second category is 
01614     '1', etc. Because each response is represented by a single character care must be 
01615     taken when some items have more than 10 response categories. For example, a response 
01616     in the 11th response category would be represented by the ascii character ':', which 
01617     is the 10th character greater than '0' in the ascii character sequence.
01618    
01619     \section function_args Function Parameters
01620   
01621     \param[in]  examineeno  Number of examinee for whom item responses are returned.
01622    */
01623 
01624   const char *examinee_response_str(int examineeno)
01625   {
01626     const char *fname = "examinee_response_str";
01627     CheckRunInit();
01628     gEtirmRun->CheckExamineeNumber(examineeno, fname);
01629 
01630     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01631 
01632     if ((gEtirmRun->items).size() != examinee->NumItems())
01633     {
01634       throw RuntimeError("Number of examinee responses does not match number of items", fname);
01635     }
01636 
01637     // iterators to first and one past last response
01638     examinee_type::response_iterator first = examinee->responses_begin();
01639     examinee_type::response_iterator last = examinee->responses_end();
01640 
01641     std::string &responseStr = gEtirmRun->returnString;
01642     responseStr.clear();
01643     ItemVector::iterator ii = (gEtirmRun->items).begin();
01644     while (first != last)
01645     {
01646       responseStr.push_back(Resp2Char(*first, *ii));
01647       ++ii;
01648       ++first;
01649     }
01650 
01651     return responseStr.c_str();
01652   }
01653 
01654   /*!
01655     \brief
01656     Return the number of the group the examinee belongs to.
01657     
01658     \section function_args Function Parameters
01659   
01660     \param[in]  examineeno  Number of examinee for whom group membership is to be returned.
01661    */
01662 
01663   int examinee_get_group(int examineeno)
01664   {
01665     CheckRunInit();
01666     gEtirmRun->CheckExamineeNumber(examineeno, "examinee_group");
01667 
01668     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01669 
01670     return examinee->Group();
01671   }
01672 
01673   /*!
01674     \brief
01675     Assigns which group the examinee belongs to.
01676     
01677     \section function_args Function Parameters
01678   
01679     \param[in]  examineeno  Number of examinee for whom group membership is to be assigned.
01680     \param[in]  group   Group number to be assigned to examinee.
01681    */
01682   void examinee_set_group(int examineeno, int group)
01683   {
01684     CheckRunInit();
01685     gEtirmRun->CheckExamineeNumber(examineeno, "examinee_set_group");
01686 
01687     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01688 
01689     return examinee->SetGroup(group);
01690   }
01691 
01692   /*!
01693     \brief
01694     Assigns the count (or weight) of the examinee.
01695     
01696     \section function_args Function Parameters
01697   
01698     \param[in]  examineeno  Number of examinee whose count (or weight) is to be assigned.
01699     \param[in]  count   Count to be assigned to examinee.
01700    */
01701   void examinee_set_count(int examineeno, double count)
01702   {
01703     CheckRunInit();
01704     gEtirmRun->CheckExamineeNumber(examineeno, "examinee_set_count");
01705 
01706     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01707 
01708     examinee->SetCount(count);
01709   }
01710 
01711   /*!
01712     \brief
01713     Returns the count (or weight) of the examinee.
01714     
01715     \section function_args Function Parameters
01716   
01717     \param[in]  examineeno  Number of examinee whose count (or weight) is to be returned.
01718    */
01719   double examinee_get_count(int examineeno)
01720   {
01721     CheckRunInit();
01722     gEtirmRun->CheckExamineeNumber(examineeno, "examinee_get_count");
01723 
01724     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01725 
01726     return examinee->Count();
01727   }
01728 
01729   /*!
01730     \brief
01731     Assigns posterior distribution of an examinee.
01732     
01733     \section function_args Function Parameters
01734   
01735     \param[in]  examineeno  Number of examinee whose posterior is to be assigned.
01736     \param[in]  *posterior  Pointer to vector of posterior probabilities of the examinee.
01737    */
01738   void examinee_set_posterior(int examineeno, double_vector *posterior)
01739   {
01740     CheckRunInit();
01741     gEtirmRun->CheckExamineeNumber(examineeno, "examinee_set_posterior");
01742 
01743     if (posterior->size() != (gEtirmRun->latentDist).size())
01744     {
01745       throw RuntimeError("Invalid number of posterior probabilities",
01746           "examinee_set_posterior");
01747     }
01748 
01749     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01750 
01751     examinee_type::posterior_vector epost(gEtirmRun->numLatentCat);
01752     examinee_type::posterior_vector::iterator iep = epost.begin();
01753     double_vector::iterator ip = posterior->begin();
01754 
01755     // assign probabilities
01756     int i;
01757     Real sum = 0.0;
01758     for (i = gEtirmRun->numLatentCat; i--; ++iep, ++ip)
01759     {
01760       *iep = *ip;
01761       sum += *iep;
01762     }
01763 
01764     // standardize probabilities to sum to 1.0
01765     iep = epost.begin();
01766     for (i = gEtirmRun->numLatentCat; i--; ++iep)
01767     {
01768       *iep /= sum;
01769     }
01770 
01771     examinee->SetPosterior(epost);
01772   }
01773 
01774   /*!
01775     \brief
01776     Returns pointer to vector of the posterior distribution of an examinee.
01777     
01778     \section function_args Function Parameters
01779   
01780     \param[in]  examineeno  Number of examinee whose posterior is to be returned.
01781    */ 
01782   double_vector* examinee_get_posterior(int examineeno)
01783   {
01784     char *fname = "examinee_get_posterior";
01785     CheckRunInit();
01786     gEtirmRun->CheckExamineeNumber(examineeno, fname);
01787 
01788     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01789     int n = examinee->NumLatentVarCat();
01790 
01791     if (n == 0)
01792     {
01793       char merr[100];
01794       std::sprintf(merr, "Posterior has not been computed for examinee %d", examineeno);
01795       gEtirmRun->returnString = merr;
01796       throw RuntimeError((gEtirmRun->returnString).c_str(), fname);
01797     }
01798 
01799     double_vector *post = new double_vector(n);
01800 
01801     examinee_type::posterior_vector::iterator ie = examinee->posterior_begin();
01802     double_vector::iterator ip = post->begin();
01803     for (; n--; ++ie, ++ip)
01804     {
01805       *ip = *ie;
01806     }
01807 
01808     return post;
01809   }
01810 
01811   /*!
01812     \brief
01813     Returns means of an examinee's posterior distribution.
01814     
01815     Posterior must have already been computed, for example, by estep_compute.
01816 
01817     \section function_args Function Parameters
01818   
01819     \param[in]  examineeno  Number of examinee whose posterior mean is to be returned.
01820    */ 
01821   double examinee_posterior_mean(int examineeno)
01822   {
01823     char *fname = "examinee_posterior_mean";
01824     CheckRunInit();
01825     gEtirmRun->CheckExamineeNumber(examineeno, fname);
01826 
01827     examinee_type *examinee = (gEtirmRun->examinees)[examineeno-1];
01828     int n = examinee->NumLatentVarCat();
01829 
01830     if (n == 0)
01831     {
01832       char merr[100];
01833       std::sprintf(merr, "Posterior distribution has not been computed for examinee %d", examineeno);
01834       gEtirmRun->returnString = merr;
01835       throw RuntimeError((gEtirmRun->returnString).c_str(), fname);
01836     }
01837 
01838     examinee_type::posterior_vector::iterator iw = examinee->posterior_begin();
01839     lvdist_type::point_iterator ip = (gEtirmRun->latentDist).begin_points();
01840     double mean = 0.0;
01841     for (; n--; ++iw, ++ip)
01842     {
01843       mean += *ip * *iw;
01844     }
01845 
01846     return mean;
01847   }
01848 
01849   /*!
01850     \brief
01851     Returns an examinee's maximum likelihood estimate of theta.
01852     
01853     Posterior must have already been computed, for example, by estep_compute.
01854 
01855     \section function_args Function Parameters
01856   
01857     \param[in]  examineeno  Number of examinee whose theta MLE is to be returned (1 = first examinee).
01858     \param[in]  minTheta  Minimum value of theta estimate.
01859     \param[in]  maxTheta  Maximum value of theta estimate.  
01860     \param[in]  precision Length of interval in which MLE is determined to lie. This should be greater 
01861         than, roughly, 3.0e-8.
01862     \param[in]  *itemno5    Pointer to a list of item numbers of the items to use in computing examinee MLE. 
01863         If itemno5 = NULL, then all items will be used.
01864    */
01865   double examinee_theta_MLE(int examineeno, double minTheta, double maxTheta, double precision,
01866       int_vector *itemno5)
01867   {
01868     CheckRunInit();
01869     gEtirmRun->CheckExamineeNumber(examineeno, "examinee_theta_MLE");
01870 
01871     if (!gEtirmRun->base_rand_simulate)
01872     {
01873       gEtirmRun->base_rand_simulate = new random_type();
01874       gEtirmRun->rand_simulate = new boost::uniform_01<random_type>(*(gEtirmRun->base_rand_simulate));
01875     }
01876 
01877     ItemVector *sitems;
01878     if (itemno5)
01879     {
01880       sitems = new ItemVector(ItemSubset(itemno5, gEtirmRun->items, "examinee_theta_MLE"));
01881     }
01882     else
01883     {
01884       sitems = &(gEtirmRun->items);
01885     }
01886 
01887     double theta =
01888         ExamineeThetaMLE<ItemVector::iterator, examinee_type::response_vector::iterator>(minTheta,
01889             maxTheta, precision, sitems->begin(), sitems->end(), (gEtirmRun->examinees[examineeno-1])->responses_begin());
01890 
01891     if (itemno5)
01892       delete sitems;
01893 
01894     return theta;
01895   }
01896 
01897   /*!
01898     \brief
01899     Returns total examinee count in an examinee group (1, 2, ...), or across all groups.
01900     
01901     \section function_args Function Parameters
01902   
01903     \param[in]  group Group to return count for (1-offset). Specify group = 0 to return 
01904         counts across all groups.
01905    */
01906   double examinees_count(int group)
01907   {
01908     CheckRunInit();
01909     if (group != 0)
01910       gEtirmRun->CheckGroup(group, "examinee_count");
01911 
01912     return (gEtirmRun->examineeCounts)[group];
01913   }
01914 
01915   /*!
01916     \brief
01917     Assigns seed of random number generator used for bootstrap samples.
01918     
01919     \section function_args Function Parameters
01920   
01921     \param[in]  seed  Seed value, 0 <= seed <= 4,294,967,295.
01922    */
01923   void bootstrap_seed(unsigned long seed)
01924   {
01925     CheckRunInit();
01926 
01927     // convert to type used for seed in boost random number library
01928     boost::uint32_t boost_seed = seed;
01929 
01930     if (gEtirmRun->rand_boot)
01931     {
01932       gEtirmRun->rand_boot->seed(boost_seed);
01933     }
01934     else
01935     {
01936       gEtirmRun->rand_boot = new random_type(boost_seed);
01937     }
01938   }
01939 
01940   /*!
01941     \brief
01942     Generate bootstrap sample of examinees.
01943    */
01944   void bootstrap_sample()
01945   {
01946     CheckRunInit();
01947     gEtirmRun->CheckExaminees("bootstrap_sample");
01948 
01949     if (!gEtirmRun->rand_boot)
01950       gEtirmRun->rand_boot = new random_type();
01951 
01952     boost::uniform_int<random_type> urand(*(gEtirmRun->rand_boot), 1, (gEtirmRun->examinees).size());
01953 
01954     BootstrapSample((gEtirmRun->examinees).begin(), (gEtirmRun->examinees).end(), urand);
01955 
01956     // Set vector of examinee counts
01957     gEtirmRun->examineeCounts = 0.0; // initialize to zero
01958     ExamineeVector::iterator ie = (gEtirmRun->examinees).begin();
01959     for (int i = (gEtirmRun->examinees).size(); i--; ++ie)
01960     {
01961       double count = (*ie)->Count();
01962       (gEtirmRun->examineeCounts)[0] += count; // total count
01963       int group = (*ie)->Group();
01964       (gEtirmRun->examineeCounts)[group] += count; // group count
01965     }
01966   }
01967 
01968   /*!
01969     \brief
01970     Assigns seed of random number generator used for simulating item responses.
01971     
01972     \section function_args Function Parameters
01973   
01974     \param[in]  seed  Seed value, 0 <= seed <= 4,294,967,295.
01975    */  
01976   void simulate_seed(unsigned long seed)
01977   {
01978     CheckRunInit();
01979 
01980     // convert to type used for seed in boost random number library
01981     boost::uint32_t boost_seed = seed;
01982 
01983     if (gEtirmRun->base_rand_simulate)
01984     {
01985       gEtirmRun->base_rand_simulate->seed(boost_seed);
01986     }
01987     else
01988     {
01989       gEtirmRun->base_rand_simulate = new random_type(boost_seed);
01990       gEtirmRun->rand_simulate = new boost::uniform_01<random_type>(*(gEtirmRun->base_rand_simulate));
01991     }
01992   }
01993 
01994   /*!
01995     \brief
01996     Simulates item responses (integers) for a specific value of the latent variable.  
01997 
01998     Returns pointer to integer vector containing item responses, where
01999     item responses are integers from 0 to one minus the maximum
02000     number of response categories for the item.
02001     
02002     \section function_args Function Parameters
02003   
02004     \param[in]  theta Value of latent variable for which item responses are generated.
02005     \param[in]  itemno2 List of item numbers of the items for which responses will be
02006         simulated.
02007    */
02008   int_vector *simulate_responses(double theta, int_vector *itemno2)
02009   {
02010     CheckRunInit();
02011 
02012     if (!gEtirmRun->base_rand_simulate)
02013     {
02014       gEtirmRun->base_rand_simulate = new random_type();
02015       gEtirmRun->rand_simulate = new boost::uniform_01<random_type>(*(gEtirmRun->base_rand_simulate));
02016     }
02017 
02018     int_vector *resp;
02019     if (itemno2)
02020     {
02021       resp = new int_vector(itemno2->size());
02022       ItemVector sitems = ItemSubset(itemno2, gEtirmRun->items, "simulate_responses");
02023       resp->newsize(sitems.size());
02024       SimulateResponses(sitems.begin(), sitems.end(), theta, *(gEtirmRun->rand_simulate),
02025           resp->begin(), true);
02026     }
02027     else
02028     {
02029       resp = new int_vector((gEtirmRun->items).size());
02030       SimulateResponses((gEtirmRun->items).begin(), (gEtirmRun->items).end(), theta, *(gEtirmRun->rand_simulate), resp->begin(), true);
02031     }
02032 
02033     return resp;
02034   }
02035 
02036   /*!
02037     \brief
02038     Simulates item responses (characters) for a specific value of the latent variable.  
02039 
02040     Returns simulated responses in a string, where each character of the string gives a 
02041     response to one item. The first response category of an item is represented by a 
02042     '0', the second response category by a '1', etc. 
02043 
02044     Because each response is represented by a single character care must be taken when 
02045     some items have more than 10 response categories. For example, a response in the 
02046     11th response category would be represented by the ascii character ':', which is 
02047     the 10th character greater than '0' in the ascii character sequence.
02048        
02049     \section function_args Function Parameters
02050   
02051     \param[in]  theta Value of latent variable for which item responses are generated.
02052     \param[in]  itemno2 List of item numbers of the items for which responses will be
02053         simulated.
02054    */
02055   const char *simulate_response_str(double theta, int_vector *itemno2)
02056   {
02057     CheckRunInit();
02058 
02059     // Vector of integers representing simulated responses
02060     int_vector *iresp = simulate_responses(theta, itemno2);
02061 
02062     // Resize string to contain item responses
02063     std::string &responseStr = gEtirmRun->returnString;
02064     responseStr.resize(iresp->size());
02065 
02066     // Convert integers to characters
02067     int_vector::iterator ii = iresp->begin();
02068     std::string::iterator ic = responseStr.begin();
02069     for (int i = iresp->size(); i--; ++ii, ++ic)
02070     {
02071       if (*ii < 0)
02072       {
02073         *ic = item_type::NotPresentedResponse();
02074       }
02075       else
02076       {
02077         *ic = *ii + '0';
02078       }
02079     }
02080 
02081     delete iresp;
02082 
02083     return responseStr.c_str();
02084   }
02085 
02086   /*!
02087     \brief
02088     Reads item responses from an input record.  
02089 
02090     The item responses are assumed to be integers from 0 to one minus the maximum
02091     number of response categories for the item. A response representing a missing 
02092     response is assigned -1.
02093 
02094     Returns poiner to an integer vector containing thew item responses.
02095        
02096     \section function_args Function Parameters
02097   
02098     \param[in]  *line  Pointer to character string to read the item responses from.
02099     \param[in]  *offset  Pointer to vector of zero-based offsets of each item response in 'line'.
02100     \param[in]  *len   Pointer to vector of field widths for each item response.  
02101    */
02102   int_vector *get_responses(char *line, int_vector *offset, int_vector *len)
02103   {
02104     const char *fname = "get_responses";
02105     CheckRunInit();
02106 
02107     int n = offset->size();
02108 
02109     if (n != len->size())
02110     {
02111       throw InvalidArgument("Lengths of offset and length vectors do not match", fname);
02112     }
02113 
02114     int_vector *resp = new int_vector(n);
02115 
02116     int_vector::iterator ir = resp->begin();
02117     int_vector::iterator ioff = offset->begin();
02118     int_vector::iterator ilen = len->begin();
02119     Response np = Item<Real>::NotPresentedResponse();
02120     for (; n--; ++ioff, ++ilen, ++ir)
02121     {
02122       // Convert response to integer
02123       char *pos = line + *ioff + *ilen - 1;
02124       *ir = 0;
02125       int power = 1;
02126       for (int i=*ilen; i--; power *= 10, --pos)
02127       {
02128         if (*pos == np) // check for missing item response
02129         {
02130           *ir = -1;
02131           break;
02132         }
02133         else if ( (*pos < '0') && (*pos > '9')) // check that item response is valid // Sytax edited, ww, 2-24-2008.
02134         {
02135           char errstr[50];
02136           std::sprintf(errstr, "Invalid item response: %1c", *pos);
02137           gEtirmRun->returnString = errstr;
02138           throw RuntimeError((gEtirmRun->returnString).c_str(), fname);
02139         }
02140         *ir += power * (*pos - '0');
02141       }
02142     }
02143 
02144     return resp;
02145   }
02146 
02147   /*!
02148     \brief
02149     Read item responses from a string where responses to only some items are
02150     present. The responses to the remaining items are assumed to be missing.
02151 
02152     The item responses are assumed to be integers from 0 to one minus the maximum
02153     number of response categories for the item. A response representing a missing 
02154     response is assigned -1.
02155 
02156     Returns poiner to an integer vector containing thew item responses.
02157        
02158     \section function_args Function Parameters
02159   
02160     \param[in]  *line  Pointer to character string to read the item responses from.
02161     \param[in]  *offset  Pointer to vector of zero-based offsets of each item response in 'line'.
02162     \param[in]  *len   Pointer to vector of field widths for each item response.  
02163     \param[in]  *items  Pointer to vector 1-offset indices of items for which responses are read.
02164    */
02165   int_vector *get_responses_missing(char *line, int_vector *offset, int_vector *len,
02166       int_vector *items)
02167   {
02168     const char *fname = "get_responses_missing";
02169     CheckRunInit();
02170 
02171     int n = offset->size();
02172 
02173     if (n != len->size() || n != items->size())
02174     {
02175       throw InvalidArgument("Lengths of vector arguments do not match", fname);
02176     }
02177 
02178     int_vector *resp = get_responses(line, offset, len);
02179 
02180     // initially assign all missing responses
02181     int nall = gEtirmRun->numItems;
02182     int_vector *allresp = new int_vector(nall, -1);
02183 
02184     // Assign responses read
02185     int_vector::iterator ir = resp->begin();
02186     int_vector::iterator ii = items->begin();
02187     for (; n--; ++ii, ++ir)
02188     {
02189       if ( (*ii < 1) || (*ii > nall)) // Syntax edited, ww, 2-24-2008.
02190       {
02191         delete resp;
02192         throw InvalidArgument("Invalid item number", fname);
02193       }
02194       (*allresp)[*ii-1] = *ir;
02195     }
02196 
02197     delete resp;
02198 
02199     return allresp;
02200   }
02201 
02202 } // namespace etirm
02203 

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