From 75557fe4b7b38d8de4e7d2f1f836c230539ac14b Mon Sep 17 00:00:00 2001 From: James J Balamuta Date: Sun, 20 Jan 2019 16:08:30 -0600 Subject: [PATCH] CRAN release candidate (#5) * Revise DESCRIPTION file ordering. * Add URLs to project (update w/ doc domain) * Rename bijectionvector() and inv_bijectionvector() to attribute_bijection() and attribute_inv_bijection() * Rename `sim_alpha_matrix()` -> `sim_attribute_classes()` * Add simulation routine for subject attributes * Update Package Flags to use both C++11 and OpenMP when available. * Update README with function renames. * Improve documentation by: - Including authors - See also - Fixing in-line doc order * Add vignettes * Remove some README content covered in vignettes. * Load the package * Improve intro-paragraph to account for instructions being added that relate to the _R_ function portion. * Update NEWS file with latest release information * Improve CRAN submission comments w/ r-devel updates. * - Use 2 cores when testing - Do not install suggested packages by default - Run jobs on both release and devel versions of _R_ to save from dealing with the win-builder. * References vignettes from README (maybe?) * Add citation information --- .gitignore | 1 + .travis.yml | 11 + DESCRIPTION | 29 ++- NAMESPACE | 7 +- NEWS.md | 5 +- R/RcppExports.R | 214 ++++++++++++++---- README.Rmd | 128 ++--------- README.md | 131 ++--------- cran-comments.md | 17 +- inst/include/simcdm_RcppExports.h | 63 ++++-- man-roxygen/rrum-example.R | 2 +- man-roxygen/sim-dina-class-example.R | 4 +- man/attribute_bijection.Rd | 28 +++ ...onvector.Rd => attribute_inv_bijection.Rd} | 19 +- man/bijectionvector.Rd | 22 -- ...pha_matrix.Rd => sim_attribute_classes.Rd} | 19 +- man/sim_dina_attributes.Rd | 7 + man/sim_dina_class.Rd | 9 +- man/sim_dina_items.Rd | 3 + man/sim_eta_matrix.Rd | 21 +- man/sim_q_matrix.Rd | 18 +- man/sim_rrum_items.Rd | 4 +- man/sim_subject_attributes.Rd | 46 ++++ man/simcdm-package.Rd | 12 +- src/Makevars | 10 +- src/Makevars.win | 10 +- src/RcppExports.cpp | 93 +++++--- src/sim_dina.cpp | 41 +++- src/sim_rrum.cpp | 5 +- src/utilities.cpp | 209 +++++++++++++---- tests/testthat/test-bijections.R | 14 +- tests/testthat/test-matrix-types.R | 16 +- vignettes/.gitignore | 2 + vignettes/overview-simcdm.Rmd | 186 +++++++++++++++ vignettes/simcdm-in-packages.Rmd | 89 ++++++++ 35 files changed, 1044 insertions(+), 451 deletions(-) create mode 100644 man/attribute_bijection.Rd rename man/{inv_bijectionvector.Rd => attribute_inv_bijection.Rd} (50%) delete mode 100644 man/bijectionvector.Rd rename man/{sim_alpha_matrix.Rd => sim_attribute_classes.Rd} (57%) create mode 100644 man/sim_subject_attributes.Rd create mode 100644 vignettes/.gitignore create mode 100644 vignettes/overview-simcdm.Rmd create mode 100644 vignettes/simcdm-in-packages.Rmd diff --git a/.gitignore b/.gitignore index 56843bc..d4a59fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +inst/doc .Rproj.user .Rhistory .RData diff --git a/.travis.yml b/.travis.yml index 1476f1e..4ce96bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,16 @@ language: R sudo: false cache: packages + +env: + global: + - MAKEFLAGS="-j 2" + - _R_CHECK_FORCE_SUGGESTS_=false + +jobs: + include: + - r: devel + - r: release + after_success: - Rscript -e 'covr::codecov()' \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index 354a523..17f4ce7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,9 +2,20 @@ Package: simcdm Type: Package Title: Simulate Cognitive Diagnostic Model (CDM) Data Version: 0.0.5 -Authors@R: c(person("James Joseph", "Balamuta", email = "balamut2@illinois.edu", role = c("aut", "cre", "cph")), - person("Steven Andrew", "Culpepper", email = "sculpepp@illinois.edu", role = c("aut", "cph")), - person("Aaron", "Hudson", email = "awhudson@uw.edu", role = c("ctb", "cph"))) +Authors@R: c(person("James Joseph", "Balamuta", + email = "balamut2@illinois.edu", + role = c("aut", "cre", "cph"), + comment = c(ORCID = "0000-0003-2826-8458")), + person("Steven Andrew", "Culpepper", + email = "sculpepp@illinois.edu", + role = c("aut", "cph"), + comment = c(ORCID = "0000-0003-4226-6176") + ), + person("Aaron", "Hudson", + email = "awhudson@uw.edu", + role = c("ctb", "cph") + ) + ) Description: Provides efficient R and 'C++' routines to simulate cognitive diagnostic model data for Deterministic Input, Noisy "And" Gate (DINA) and reduced Reparameterized Unified Model (rRUM) from @@ -13,12 +24,18 @@ Description: Provides efficient R and 'C++' routines to simulate cognitive diagn de la Torre (2009) . Depends: R (>= 3.5.0) -LinkingTo: Rcpp, RcppArmadillo (>= 0.9.200) -License: GPL (>= 2) Imports: Rcpp (>= 1.0.0) +LinkingTo: Rcpp, + RcppArmadillo (>= 0.9.200) +URL: https://github.com/tmsalab/simcdm +BugReports: https://github.com/tmsalab/simcdm/issues +License: GPL (>= 2) RoxygenNote: 6.1.1 Roxygen: list(markdown = TRUE) Encoding: UTF-8 Suggests: testthat, - covr + covr, + knitr, + rmarkdown +VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index e88bc83..d01e386 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,13 +1,14 @@ # Generated by roxygen2: do not edit by hand -export(bijectionvector) -export(inv_bijectionvector) -export(sim_alpha_matrix) +export(attribute_bijection) +export(attribute_inv_bijection) +export(sim_attribute_classes) export(sim_dina_attributes) export(sim_dina_class) export(sim_dina_items) export(sim_eta_matrix) export(sim_q_matrix) export(sim_rrum_items) +export(sim_subject_attributes) importFrom(Rcpp,evalCpp) useDynLib(simcdm, .registration=TRUE) diff --git a/NEWS.md b/NEWS.md index 8e4caec..b2ab7f6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# simcdm 0.0.4 +# simcdm 0.0.5 - Added _C++_ and _R_ functions for simulation of: - Deterministic Input, Noisy "And" Gate (DINA) @@ -9,4 +9,5 @@ - Matrices: - Random Q Matrix: `sim_q_matrix()` - ETA Matrix: `sim_eta_matrix()` - - Latent Attribute Profile Matrix: `sim_alpha_matrix()` + - Latent Attribute Profile Matrix: `sim_attribute_classes()` + - Latent Attribute Profiles for Subjects: `sim_subject_attributes()` diff --git a/R/RcppExports.R b/R/RcppExports.R index 186c74b..6eff000 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -16,10 +16,17 @@ #' the probability of an incorrect response for individuals with #' all of the required attributes #' -#' @return A dichotomous item matrix -#' @author Steven Andrew Culpepper and James Joseph Balamuta -#' @template sim-dina-class-example +#' @return +#' A dichotomous item matrix with dimensions \eqn{N \times J}{N x J}. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::sim_dina_attributes()] and [simcdm::sim_dina_items()] +#' #' @export +#' @template sim-dina-class-example sim_dina_class <- function(N, J, CLASS, ETA, gs, ss) { .Call(`_simcdm_sim_dina_class`, N, J, CLASS, ETA, gs, ss) } @@ -28,10 +35,21 @@ sim_dina_class <- function(N, J, CLASS, ETA, gs, ss) { #' #' Generates a DINA model's \eqn{\eta} matrix based on alphas and #' the \eqn{\mathbf{Q}} matrix. +#' #' @inheritParams sim_dina_items -#' @author Steven Andrew Culpepper and James Joseph Balamuta -#' @template sim-dina-example-body +#' +#' @return +#' The \eqn{\eta} `matrix` with dimensions \eqn{N \times J}{N x J} under +#' the DINA model. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::sim_dina_class()] and [simcdm::sim_dina_items()] +#' #' @export +#' @template sim-dina-example-body sim_dina_attributes <- function(alphas, Q) { .Call(`_simcdm_sim_dina_attributes`, alphas, Q) } @@ -48,10 +66,17 @@ sim_dina_attributes <- function(alphas, Q) { #' @param ss A \eqn{J} `vector` of item slipping parameters. #' @param gs A \eqn{J} `vector` of item guessing parameters. #' -#' @return A \eqn{N} by \eqn{J} `matrix` of responses from the DINA model. -#' @author Steven Andrew Culpepper and James Joseph Balamuta -#' @template sim-dina-example-body +#' @return +#' A \eqn{N} by \eqn{J} `matrix` of responses from the DINA model. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::sim_dina_class()] and [simcdm::sim_dina_attributes()] +#' #' @export +#' @template sim-dina-example-body sim_dina_items <- function(alphas, Q, ss, gs) { .Call(`_simcdm_sim_dina_items`, alphas, Q, ss, gs) } @@ -85,11 +110,12 @@ sim_rrum_main <- function(Q, rstar, pistar, alpha) { #' the number of attributes. An entry of 1 indicates individual #' \eqn{i} has attained attribute \eqn{k}. An entry of 0 #' indicates the attribute has not been attained. -#' #' @return Y A `matrix` with \eqn{N} rows and \eqn{J} columns indicating #' the indviduals' responses to each of the items, where \eqn{J} #' represents the number of items. -#' @author Steven Andrew Culpepper and James Joseph Balamuta +#' @author +#' Steven Andrew Culpepper, Aaron Hudson, and James Joseph Balamuta +#' #' @export #' @template rrum-example #' @template rrum-references @@ -97,52 +123,83 @@ sim_rrum_items <- function(Q, rstar, pistar, alpha) { .Call(`_simcdm_sim_rrum_items`, Q, rstar, pistar, alpha) } -#' Bijection Vector +#' Constructs Unique Attribute Pattern Map #' -#' Computes the powers of 2 from \eqn{0} up to \eqn{K - 1}. +#' Computes the powers of 2 from \eqn{0} up to \eqn{K - 1} for +#' \eqn{K}-dimensional attribute pattern. +#' #' @param K Number of Attributes. -#' @return A \code{vec} with length \eqn{K} detailing the power's of 2. -#' @examples -#' -#' bijectionvector(3) -#' +#' +#' @return +#' A \code{vec} with length \eqn{K} detailing the power's of 2. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::attribute_inv_bijection()] +#' #' @export -bijectionvector <- function(K) { - .Call(`_simcdm_bijectionvector`, K) +#' @examples +#' ## Construct an attribute bijection ---- +#' biject = attribute_bijection(3) +attribute_bijection <- function(K) { + .Call(`_simcdm_attribute_bijection`, K) } #' Perform an Inverse Bijection of an Integer to Attribute Pattern #' -#' Convert integer between \eqn{0} and \eqn{2^{K-1}} to +#' Convert an integer between \eqn{0} and \eqn{2^{K-1}} to #' \eqn{K}-dimensional attribute pattern. #' #' @param CL An `integer` between \eqn{0} and \eqn{2^{K-1}} -#' @inheritParams bijectionvector -#' @return A \eqn{K}-dimensional vector with an attribute pattern corresponding +#' @inheritParams attribute_bijection +#' +#' @return +#' A \eqn{K}-dimensional vector with an attribute pattern corresponding #' to `CL`. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::attribute_bijection()] +#' #' @export -#' #' @examples -#' inv_bijectionvector(5, 1) -#' inv_bijectionvector(5, 2) -inv_bijectionvector <- function(K, CL) { - .Call(`_simcdm_inv_bijectionvector`, K, CL) +#' ## Construct an attribute inversion bijection ---- +#' inv_biject1 = attribute_inv_bijection(5, 1) +#' inv_biject2 = attribute_inv_bijection(5, 2) +attribute_inv_bijection <- function(K, CL) { + .Call(`_simcdm_attribute_inv_bijection`, K, CL) } -#' Generate random Q matrix +#' Generate a Random Identifiable Q Matrix #' #' Simulates a Q matrix containing three identity matrices after a row -#' permutation. +#' permutation that is identifiable. #' #' @param J Number of Items #' @param K Number of Attributes #' -#' @return A dichotomous \code{matrix} for Q. -#' @examples -#' sim_q_matrix(7, 2) +#' @return +#' A dichotomous \code{matrix} for Q. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::attribute_bijection()] and [simcdm::attribute_inv_bijection()] #' -#' sim_q_matrix(10, 3) #' @export +#' @examples +#' ## Simulate identifiable Q matrices ---- +#' +#' # 7 items and 2 attributes +#' q_matrix_j7_k2 = sim_q_matrix(7, 2) +#' +#' # 10 items and 3 attributes +#' q_matrix_j10_k3 = sim_q_matrix(10, 3) sim_q_matrix <- function(J, K) { .Call(`_simcdm_sim_q_matrix`, J, K) } @@ -154,15 +211,28 @@ sim_q_matrix <- function(J, K) { #' @param K Number of Attribute Levels #' @param J Number of Assessment Items #' @param Q Q Matrix with dimensions \eqn{K \times J}{K x J}. -#' @return A `mat` with dimensions \eqn{J \times 2^K}{J x 2^K}. +#' +#' @return +#' A `mat` with dimensions \eqn{J \times 2^K}{J x 2^K}. +#' +#' @author +#' Steven Andrew Culpepper and James Joseph Balamuta +#' +#' @seealso +#' [simcdm::sim_q_matrix()], [simcdm::attribute_bijection()], and +#' [simcdm::attribute_inv_bijection()] +#' #' @export -#' #' @examples +#' ## Simulation Settings ---- +#' #' # Fixed Number of Assessment Items for Q #' J = 18 #' #' # Fixed Number of Attributes for Q -#' K = 3 +#' K = 3 +#' +#' ## Pre-specified configuration ---- #' #' # Specify Q #' qbj = c(4, 2, 1, 4, 2, 1, 4, 2, 1, 6, 5, 3, 6, 5, 3, 7, 7, 7) @@ -170,45 +240,93 @@ sim_q_matrix <- function(J, K) { #' # Fill Q Matrix #' Q = matrix(, J, K) #' for (j in seq_len(J)) { -#' Q[j,] = inv_bijectionvector(K, qbj[j]) +#' Q[j,] = attribute_inv_bijection(K, qbj[j]) #' } #' #' # Create an eta matrix #' ETA = sim_eta_matrix(K, J, Q) #' -#' # Generate an ETA matrix for a random Q. +#' ## Random generation of Q matrix with ETA matrix ---- #' -#' # Create an eta matrix +#' # Construct a random q matrix #' Q_sim = sim_q_matrix(J, K) +#' +#' # Generate the eta matrix #' ETA_gen = sim_eta_matrix(K, J, Q_sim) sim_eta_matrix <- function(K, J, Q) { .Call(`_simcdm_sim_eta_matrix`, K, J, Q) } -#' Simulate the Latent Attribute Profile Matrix \eqn{\mathbf{\alpha}_c} +#' Simulate all the Latent Attribute Profile \eqn{\mathbf{\alpha}_c} in Matrix form #' #' Generate the \eqn{\mathbf{\alpha}_c = (\alpha_{c1}, \ldots, \alpha_{cK})'} #' attribute profile matrix for members of class \eqn{c} such that \eqn{\alpha_{ck}} #' is 1 if members of class \eqn{c} possess skill \eqn{k} and zero otherwise. #' -#' @param K Number of Skills +#' @param K Number of Attributes #' -#' @return A \eqn{2^K} by \eqn{K} `matrix` of latent classes +#' @return +#' A \eqn{2^K} by \eqn{K} `matrix` of latent classes #' corresponding to entry \eqn{c} of \eqn{pi} based upon #' mastery and nonmastery of the \eqn{K} skills. #' -#' @author James Joseph Balamuta and Steven Andrew Culpepper +#' @author +#' James Joseph Balamuta and Steven Andrew Culpepper #' -#' @export +#' @seealso +#' [simcdm::sim_subject_attributes()] and [simcdm::attribute_inv_bijection()] #' +#' @export #' @examples -#' # Define test parameters and traits +#' ## Simulate Attribute Class Matrix ---- +#' +#' # Define number of attributes #' K = 3 #' #' # Generate an Latent Attribute Profile (Alpha) Matrix -#' alphas = sim_alpha_matrix(K) -sim_alpha_matrix <- function(K) { - .Call(`_simcdm_sim_alpha_matrix`, K) +#' alphas = sim_attribute_classes(K) +sim_attribute_classes <- function(K) { + .Call(`_simcdm_sim_attribute_classes`, K) +} + +#' Simulate Subject Latent Attribute Profiles \eqn{\mathbf{\alpha}_c} +#' +#' Generate a sample from the +#' \eqn{\mathbf{\alpha}_c = (\alpha_{c1}, \ldots, \alpha_{cK})'} +#' attribute profile matrix for members of class \eqn{c} such that \eqn{\alpha_{ck}} +#' is 1 if members of class \eqn{c} possess skill \eqn{k} and zero otherwise. +#' +#' @param N Number of Observations +#' @param K Number of Skills +#' @param probs A `vector` of probabilities that sum to 1. +#' +#' @return +#' A \eqn{N} by \eqn{K} `matrix` of latent classes +#' corresponding to entry \eqn{c} of \eqn{pi} based upon +#' mastery and nonmastery of the \eqn{K} skills. +#' +#' @author +#' James Joseph Balamuta and Steven Andrew Culpepper +#' +#' @seealso +#' [simcdm::sim_attribute_classes()] and [simcdm::attribute_inv_bijection()] +#' +#' @export +#' @examples +#' # Define number of subjects and attributes +#' N = 100 +#' K = 3 +#' +#' # Generate a sample from the Latent Attribute Profile (Alpha) Matrix +#' # By default, we sample from a uniform distribution weighting of classes. +#' alphas_builtin = sim_subject_attributes(N, K) +#' +#' # Generate a sample using custom probabilities from the +#' # Latent Attribute Profile (Alpha) Matrix +#' probs = rep(1 / (2 ^ K), 2 ^ K) +#' alphas_custom = sim_subject_attributes(N, K, probs) +sim_subject_attributes <- function(N, K, probs = NULL) { + .Call(`_simcdm_sim_subject_attributes`, N, K, probs) } # Register entry points for exported C++ functions diff --git a/README.Rmd b/README.Rmd index a1bddb4..f6c4e7e 100644 --- a/README.Rmd +++ b/README.Rmd @@ -20,7 +20,8 @@ knitr::opts_chunk$set( [![Downloads](http://cranlogs.r-pkg.org/badges/simcdm?color=brightgreen)](http://www.r-pkg.org/pkg/simcdm) [![Coverage status](https://codecov.io/gh/tmsalab/simcdm/branch/master/graph/badge.svg)](https://codecov.io/github/tmsalab/simcdm?branch=master) -The goal of simcdm is to simulate cognitive diagnostic model data. +The goal of `simcdm` is to provide flexible ways to simulate data under +cognitive diagnostic models. ## Installation @@ -39,127 +40,38 @@ To use `simcdm`, load the package using: library("simcdm") ``` +## Overview + There are three distinct sets of functions within the package: -- Matrix: `sim_q_matrix()`, `sim_eta_matrix()`, and `sim_alpha_matrix()`. +- Matrix: `sim_q_matrix()`, `sim_eta_matrix()`, `sim_attribute_classes()`, and `sim_subject_attributes()`. - Deterministic Input, Noisy And Gate (DINA): `sim_dina_items()` and `sim_dina_attributes()` - reduced Reparameterized Unified Model (rRUM): `sim_rrum_items()` -Notice that all functions in the package are named with the prefix of `sim_*()`. -This is done to all you to quickly find functions using autocomplete inside -of _RStudio_. - -### Matrix Simulation - -```{r} -# Set a seed for reproducibility -set.seed(888) - -# Setup Parameters -N = 500 # Number of Examinees / Subjects -J = 10 # Number of Items -K = 2 # Number of Skills / Attributes - -# Simulate a Q matrix (J items by K skills) -Q = sim_q_matrix(J, K) - -# Create the ideal response matrix for each trait (J items by 2^K latent classes) -eta = sim_eta_matrix(K, J, Q) - -# Generate latent attribute profile matrix (2^K latent classes by K skills) -alphas = sim_alpha_matrix(K) -``` - -### DINA Simulation - -```{r} -# Assign slipping and guessing values -ss = gs = rep(.2, J) - -# Simulate item data under DINA model -dina_items = sim_dina_items(alphas, Q, ss, gs) - -# Simulate attribute data under DINA model -dina_attributes = sim_dina_attributes(alphas, Q) -``` - -### rRUM Simulation - -```{r} -# The probabilities of answering each item correctly for individuals -# who do not lack any required attribute -pistar = rep(.9, J) - -# Penalties for failing to have each of the required attributes -rstar = .5 * Q - -# Latent Class Probabilities -pis = c(.1, .2, .3, .4) - -# Pick an attribute profile -alpha_local = alphas[sample(K ^ 2, N, replace = TRUE, pis),] +Note that all functions in the package are named with the prefix of `sim_*()`. +This is done to allow for functions to be quickly identified and used through +autocomplete inside of the [RStudio IDE](https://www.rstudio.com). -# Simulate rum items -rrum_items = sim_rrum_items(Q, rstar, pistar, alpha_local) -``` - -### Package usage - -The design of `simcdm` allows the package to be included in other _R_ packages -using either the _R_ or _C++_ functions. The next section details how to -incorporate the _C++_ code into the package or standalone _C++_ file. - -Note, if you are not familiar with compiled code in _R_ please -feel free to use the traditional way to import the _R_ functions. - -#### C++ Standalone Usage - -Within the a _C++_ file in `src/`, then add: - -```cpp -#include -#include - -// [[Rcpp::depends(simcdm, RcppArmadillo)]] - -// [[Rcpp::export]] -arma::mat example_dina_sim(const arma::mat &alphas, const arma::mat &Q, - const arma::vec &ss, const arma::vec &gs) { - - arma::mat dina_items = simcdm::sim_dina_items(alphas, Q, ss, gs); - - return dina_items; -} -``` +For more details, please see the [package vignettes](vignettes/): -#### C++ Package +- [Overview of `simcdm`](vignettes/overview-simcdm.html) +- [Using `simcdm` in R packages](vignettes/simcdm-in-packages.html) -To use `simcdm` in your R package, modify the `DESCRIPTION` file by adding: +## Authors - LinkingTo: Rcpp, RcppArmadillo (>= 0.9.200), simcdm - Imports: - Rcpp (>= 1.0.0) +James Joseph Balamuta and Steven Andrew Culpepper +with contributions from Aaron Hudson. -Reference the simulation functions using `simcdm` namespace like so: +## Citing the `simcdm` package -```cpp -#include +To ensure future development of the package, please cite `simcdm` package if +used during the analysis or simulations. Citation information for the package +may be acquired by using in _R_: -// [[Rcpp::export]] -arma::mat example_rrum_sim(const arma::mat &Q, const arma::mat &rstar, - const arma::vec &pistar, const arma::mat &alpha) { - - arma::mat rrum_items = simcdm::sim_rrum_items(Q, rstar, pistar, alpha); - - return rrum_items; -} +```{r, eval = FALSE} +citation("simcdm") ``` -## Authors - -James Joseph Balamuta and Steven Andrew Culpepper -with contributions from Aaron Hudson. - ## License GPL (>= 2) diff --git a/README.md b/README.md index fc57a2c..f6145f0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ Status](https://travis-ci.org/tmsalab/simcdm.svg)](https://travis-ci.org/tmsalab [![Coverage status](https://codecov.io/gh/tmsalab/simcdm/branch/master/graph/badge.svg)](https://codecov.io/github/tmsalab/simcdm?branch=master) -The goal of simcdm is to simulate cognitive diagnostic model data. +The goal of `simcdm` is to provide flexible ways to simulate data under +cognitive diagnostic models. ## Installation @@ -30,131 +31,41 @@ To use `simcdm`, load the package using: library("simcdm") ``` +## Overview + There are three distinct sets of functions within the package: - - Matrix: `sim_q_matrix()`, `sim_eta_matrix()`, and - `sim_alpha_matrix()`. + - Matrix: `sim_q_matrix()`, `sim_eta_matrix()`, + `sim_attribute_classes()`, and `sim_subject_attributes()`. - Deterministic Input, Noisy And Gate (DINA): `sim_dina_items()` and `sim_dina_attributes()` - reduced Reparameterized Unified Model (rRUM): `sim_rrum_items()` -Notice that all functions in the package are named with the prefix of -`sim_*()`. This is done to all you to quickly find functions using -autocomplete inside of *RStudio*. - -### Matrix Simulation - -``` r -# Set a seed for reproducibility -set.seed(888) - -# Setup Parameters -N = 500 # Number of Examinees / Subjects -J = 10 # Number of Items -K = 2 # Number of Skills / Attributes +Note that all functions in the package are named with the prefix of +`sim_*()`. This is done to allow for functions to be quickly identified +and used through autocomplete inside of the [RStudio +IDE](https://www.rstudio.com). -# Simulate a Q matrix (J items by K skills) -Q = sim_q_matrix(J, K) +For more details, please see the [package vignettes](vignettes/): -# Create the ideal response matrix for each trait (J items by 2^K latent classes) -eta = sim_eta_matrix(K, J, Q) + - [Overview of `simcdm`](vignettes/overview-simcdm.html) + - [Using `simcdm` in R packages](vignettes/simcdm-in-packages.html) -# Generate latent attribute profile matrix (2^K latent classes by K skills) -alphas = sim_alpha_matrix(K) -``` - -### DINA Simulation - -``` r -# Assign slipping and guessing values -ss = gs = rep(.2, J) +## Authors -# Simulate item data under DINA model -dina_items = sim_dina_items(alphas, Q, ss, gs) +James Joseph Balamuta and Steven Andrew Culpepper with contributions +from Aaron Hudson. -# Simulate attribute data under DINA model -dina_attributes = sim_dina_attributes(alphas, Q) -``` +## Citing the `simcdm` package -### rRUM Simulation +To ensure future development of the package, please cite `simcdm` +package if used during the analysis or simulations. Citation information +for the package may be acquired by using in *R*: ``` r -# The probabilities of answering each item correctly for individuals -# who do not lack any required attribute -pistar = rep(.9, J) - -# Penalties for failing to have each of the required attributes -rstar = .5 * Q - -# Latent Class Probabilities -pis = c(.1, .2, .3, .4) - -# Pick an attribute profile -alpha_local = alphas[sample(K ^ 2, N, replace = TRUE, pis),] - -# Simulate rum items -rrum_items = sim_rrum_items(Q, rstar, pistar, alpha_local) -``` - -### Package usage - -The design of `simcdm` allows the package to be included in other *R* -packages using either the *R* or *C++* functions. The next section -details how to incorporate the *C++* code into the package or standalone -*C++* file. - -Note, if you are not familiar with compiled code in *R* please feel free -to use the traditional way to import the *R* functions. - -#### C++ Standalone Usage - -Within the a *C++* file in `src/`, then add: - -``` cpp -#include -#include - -// [[Rcpp::depends(simcdm, RcppArmadillo)]] - -// [[Rcpp::export]] -arma::mat example_dina_sim(const arma::mat &alphas, const arma::mat &Q, - const arma::vec &ss, const arma::vec &gs) { - - arma::mat dina_items = simcdm::sim_dina_items(alphas, Q, ss, gs); - - return dina_items; -} +citation("simcdm") ``` -#### C++ Package - -To use `simcdm` in your R package, modify the `DESCRIPTION` file by -adding: - - LinkingTo: Rcpp, RcppArmadillo, simcdm - Imports: - Rcpp (>= 1.0.0) - -Reference the simulation functions using `simcdm` namespace like so: - -``` cpp -#include - -// [[Rcpp::export]] -arma::mat example_rrum_sim(const arma::mat &Q, const arma::mat &rstar, - const arma::vec &pistar, const arma::mat &alpha) { - - arma::mat rrum_items = simcdm::sim_rrum_items(Q, rstar, pistar, alpha); - - return rrum_items; -} -``` - -## Authors - -James Joseph Balamuta and Steven Andrew Culpepper with contributions -from Aaron Hudson. - ## License GPL (\>= 2) diff --git a/cran-comments.md b/cran-comments.md index 3636e03..af5dc49 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,6 +1,6 @@ ## Test environments -* local OS X install, R 3.4.2 -* ubuntu 12.04 (on travis-ci), R 3.4.2 +* local OS X install, R 3.5.2 +* ubuntu 14.04 (on travis-ci), R 3.5.2 * win-builder (devel and release) ## R CMD check results @@ -11,7 +11,10 @@ New submission Possibly mis-spelled words in DESCRIPTION: CDM (3:45) - rRUM (9:42) + Culpepper (22:5, 23:5) + Torre (24:11) + de (24:5) + rRUM (21:44) Found the following (possibly) invalid URLs: URL: http://www.r-pkg.org/pkg/simcdm (moved to https://www.r-pkg.org:443/pkg/simcdm) @@ -20,10 +23,12 @@ Found the following (possibly) invalid URLs: Message: Not Found - This is a new release. As a result, the package has yet to be listed on - r-pkg, which is why the URL is failing. Lastly, CDM and rRUM are the appropriate - acronyms for Deterministic Input, Noisy "And" Gate (DINA) and + r-pkg, which is why the URL is failing. +- Regarding mis-spellings: + - CDM and rRUM are the appropriate acronyms for + Deterministic Input, Noisy "And" Gate (DINA) and reduced Reparameterized Unified Model (rRUM). - + - `Culpepper`, `de`, and `Torre` are either parts of names or lastnames. ## Reverse dependencies diff --git a/inst/include/simcdm_RcppExports.h b/inst/include/simcdm_RcppExports.h index 9fe16ce..6272b1d 100644 --- a/inst/include/simcdm_RcppExports.h +++ b/inst/include/simcdm_RcppExports.h @@ -130,17 +130,17 @@ namespace simcdm { return Rcpp::as(rcpp_result_gen); } - inline arma::vec bijectionvector(unsigned int K) { - typedef SEXP(*Ptr_bijectionvector)(SEXP); - static Ptr_bijectionvector p_bijectionvector = NULL; - if (p_bijectionvector == NULL) { - validateSignature("arma::vec(*bijectionvector)(unsigned int)"); - p_bijectionvector = (Ptr_bijectionvector)R_GetCCallable("simcdm", "_simcdm_bijectionvector"); + inline arma::vec attribute_bijection(unsigned int K) { + typedef SEXP(*Ptr_attribute_bijection)(SEXP); + static Ptr_attribute_bijection p_attribute_bijection = NULL; + if (p_attribute_bijection == NULL) { + validateSignature("arma::vec(*attribute_bijection)(unsigned int)"); + p_attribute_bijection = (Ptr_attribute_bijection)R_GetCCallable("simcdm", "_simcdm_attribute_bijection"); } RObject rcpp_result_gen; { RNGScope RCPP_rngScope_gen; - rcpp_result_gen = p_bijectionvector(Shield(Rcpp::wrap(K))); + rcpp_result_gen = p_attribute_bijection(Shield(Rcpp::wrap(K))); } if (rcpp_result_gen.inherits("interrupted-error")) throw Rcpp::internal::InterruptedException(); @@ -151,17 +151,17 @@ namespace simcdm { return Rcpp::as(rcpp_result_gen); } - inline arma::vec inv_bijectionvector(unsigned int K, double CL) { - typedef SEXP(*Ptr_inv_bijectionvector)(SEXP,SEXP); - static Ptr_inv_bijectionvector p_inv_bijectionvector = NULL; - if (p_inv_bijectionvector == NULL) { - validateSignature("arma::vec(*inv_bijectionvector)(unsigned int,double)"); - p_inv_bijectionvector = (Ptr_inv_bijectionvector)R_GetCCallable("simcdm", "_simcdm_inv_bijectionvector"); + inline arma::vec attribute_inv_bijection(unsigned int K, double CL) { + typedef SEXP(*Ptr_attribute_inv_bijection)(SEXP,SEXP); + static Ptr_attribute_inv_bijection p_attribute_inv_bijection = NULL; + if (p_attribute_inv_bijection == NULL) { + validateSignature("arma::vec(*attribute_inv_bijection)(unsigned int,double)"); + p_attribute_inv_bijection = (Ptr_attribute_inv_bijection)R_GetCCallable("simcdm", "_simcdm_attribute_inv_bijection"); } RObject rcpp_result_gen; { RNGScope RCPP_rngScope_gen; - rcpp_result_gen = p_inv_bijectionvector(Shield(Rcpp::wrap(K)), Shield(Rcpp::wrap(CL))); + rcpp_result_gen = p_attribute_inv_bijection(Shield(Rcpp::wrap(K)), Shield(Rcpp::wrap(CL))); } if (rcpp_result_gen.inherits("interrupted-error")) throw Rcpp::internal::InterruptedException(); @@ -214,17 +214,38 @@ namespace simcdm { return Rcpp::as(rcpp_result_gen); } - inline arma::mat sim_alpha_matrix(int K) { - typedef SEXP(*Ptr_sim_alpha_matrix)(SEXP); - static Ptr_sim_alpha_matrix p_sim_alpha_matrix = NULL; - if (p_sim_alpha_matrix == NULL) { - validateSignature("arma::mat(*sim_alpha_matrix)(int)"); - p_sim_alpha_matrix = (Ptr_sim_alpha_matrix)R_GetCCallable("simcdm", "_simcdm_sim_alpha_matrix"); + inline arma::mat sim_attribute_classes(int K) { + typedef SEXP(*Ptr_sim_attribute_classes)(SEXP); + static Ptr_sim_attribute_classes p_sim_attribute_classes = NULL; + if (p_sim_attribute_classes == NULL) { + validateSignature("arma::mat(*sim_attribute_classes)(int)"); + p_sim_attribute_classes = (Ptr_sim_attribute_classes)R_GetCCallable("simcdm", "_simcdm_sim_attribute_classes"); } RObject rcpp_result_gen; { RNGScope RCPP_rngScope_gen; - rcpp_result_gen = p_sim_alpha_matrix(Shield(Rcpp::wrap(K))); + rcpp_result_gen = p_sim_attribute_classes(Shield(Rcpp::wrap(K))); + } + if (rcpp_result_gen.inherits("interrupted-error")) + throw Rcpp::internal::InterruptedException(); + if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen)) + throw Rcpp::LongjumpException(rcpp_result_gen); + if (rcpp_result_gen.inherits("try-error")) + throw Rcpp::exception(Rcpp::as(rcpp_result_gen).c_str()); + return Rcpp::as(rcpp_result_gen); + } + + inline arma::mat sim_subject_attributes(int N, int K, Rcpp::Nullable probs = R_NilValue) { + typedef SEXP(*Ptr_sim_subject_attributes)(SEXP,SEXP,SEXP); + static Ptr_sim_subject_attributes p_sim_subject_attributes = NULL; + if (p_sim_subject_attributes == NULL) { + validateSignature("arma::mat(*sim_subject_attributes)(int,int,Rcpp::Nullable)"); + p_sim_subject_attributes = (Ptr_sim_subject_attributes)R_GetCCallable("simcdm", "_simcdm_sim_subject_attributes"); + } + RObject rcpp_result_gen; + { + RNGScope RCPP_rngScope_gen; + rcpp_result_gen = p_sim_subject_attributes(Shield(Rcpp::wrap(N)), Shield(Rcpp::wrap(K)), Shield(Rcpp::wrap(probs))); } if (rcpp_result_gen.inherits("interrupted-error")) throw Rcpp::internal::InterruptedException(); diff --git a/man-roxygen/rrum-example.R b/man-roxygen/rrum-example.R index a27d6d0..2495ea1 100644 --- a/man-roxygen/rrum-example.R +++ b/man-roxygen/rrum-example.R @@ -8,7 +8,7 @@ #' K = 2 # number of attributes #' #' # Matrix where rows represent attribute classes -#' As = sim_alpha_matrix(K) +#' As = sim_attribute_classes(K) #' #' # Latent Class probabilities #' pis = c(.1, .2, .3, .4) diff --git a/man-roxygen/sim-dina-class-example.R b/man-roxygen/sim-dina-class-example.R index 79339a3..6fffb47 100644 --- a/man-roxygen/sim-dina-class-example.R +++ b/man-roxygen/sim-dina-class-example.R @@ -13,7 +13,7 @@ #' # Fill Q Matrix #' Q = matrix(, J, K) #' for (j in seq_len(J)) { -#' Q[j,] = inv_bijectionvector(K, qbj[j]) +#' Q[j,] = attribute_inv_bijection(K, qbj[j]) #' } #' #' # Item parm vals @@ -32,7 +32,7 @@ #' X = Z %*% chol(Sig) #' thvals = matrix(rep(0, K), N, K, byrow = T) #' Alphas = 1 * (X > thvals) -#' CLs = Alphas %*% bijectionvector(K) +#' CLs = Alphas %*% attribute_bijection(K) #' } #' #' # Simulate data under DINA model diff --git a/man/attribute_bijection.Rd b/man/attribute_bijection.Rd new file mode 100644 index 0000000..45fcf08 --- /dev/null +++ b/man/attribute_bijection.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{attribute_bijection} +\alias{attribute_bijection} +\title{Constructs Unique Attribute Pattern Map} +\usage{ +attribute_bijection(K) +} +\arguments{ +\item{K}{Number of Attributes.} +} +\value{ +A \code{vec} with length \eqn{K} detailing the power's of 2. +} +\description{ +Computes the powers of 2 from \eqn{0} up to \eqn{K - 1} for +\eqn{K}-dimensional attribute pattern. +} +\examples{ +## Construct an attribute bijection ---- +biject = attribute_bijection(3) +} +\seealso{ +\code{\link[simcdm:attribute_inv_bijection]{simcdm::attribute_inv_bijection()}} +} +\author{ +Steven Andrew Culpepper and James Joseph Balamuta +} diff --git a/man/inv_bijectionvector.Rd b/man/attribute_inv_bijection.Rd similarity index 50% rename from man/inv_bijectionvector.Rd rename to man/attribute_inv_bijection.Rd index 83ebb92..8275ba0 100644 --- a/man/inv_bijectionvector.Rd +++ b/man/attribute_inv_bijection.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/RcppExports.R -\name{inv_bijectionvector} -\alias{inv_bijectionvector} +\name{attribute_inv_bijection} +\alias{attribute_inv_bijection} \title{Perform an Inverse Bijection of an Integer to Attribute Pattern} \usage{ -inv_bijectionvector(K, CL) +attribute_inv_bijection(K, CL) } \arguments{ \item{K}{Number of Attributes.} @@ -16,10 +16,17 @@ A \eqn{K}-dimensional vector with an attribute pattern corresponding to \code{CL}. } \description{ -Convert integer between \eqn{0} and \eqn{2^{K-1}} to +Convert an integer between \eqn{0} and \eqn{2^{K-1}} to \eqn{K}-dimensional attribute pattern. } \examples{ -inv_bijectionvector(5, 1) -inv_bijectionvector(5, 2) +## Construct an attribute inversion bijection ---- +inv_biject1 = attribute_inv_bijection(5, 1) +inv_biject2 = attribute_inv_bijection(5, 2) +} +\seealso{ +\code{\link[simcdm:attribute_bijection]{simcdm::attribute_bijection()}} +} +\author{ +Steven Andrew Culpepper and James Joseph Balamuta } diff --git a/man/bijectionvector.Rd b/man/bijectionvector.Rd deleted file mode 100644 index 04309a3..0000000 --- a/man/bijectionvector.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/RcppExports.R -\name{bijectionvector} -\alias{bijectionvector} -\title{Bijection Vector} -\usage{ -bijectionvector(K) -} -\arguments{ -\item{K}{Number of Attributes.} -} -\value{ -A \code{vec} with length \eqn{K} detailing the power's of 2. -} -\description{ -Computes the powers of 2 from \eqn{0} up to \eqn{K - 1}. -} -\examples{ - -bijectionvector(3) - -} diff --git a/man/sim_alpha_matrix.Rd b/man/sim_attribute_classes.Rd similarity index 57% rename from man/sim_alpha_matrix.Rd rename to man/sim_attribute_classes.Rd index b5f2e8e..5929d96 100644 --- a/man/sim_alpha_matrix.Rd +++ b/man/sim_attribute_classes.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/RcppExports.R -\name{sim_alpha_matrix} -\alias{sim_alpha_matrix} -\title{Simulate the Latent Attribute Profile Matrix \eqn{\mathbf{\alpha}_c}} +\name{sim_attribute_classes} +\alias{sim_attribute_classes} +\title{Simulate all the Latent Attribute Profile \eqn{\mathbf{\alpha}_c} in Matrix form} \usage{ -sim_alpha_matrix(K) +sim_attribute_classes(K) } \arguments{ -\item{K}{Number of Skills} +\item{K}{Number of Attributes} } \value{ A \eqn{2^K} by \eqn{K} \code{matrix} of latent classes @@ -20,11 +20,16 @@ attribute profile matrix for members of class \eqn{c} such that \eqn{\alpha_{ck} is 1 if members of class \eqn{c} possess skill \eqn{k} and zero otherwise. } \examples{ -# Define test parameters and traits +## Simulate Attribute Class Matrix ---- + +# Define number of attributes K = 3 # Generate an Latent Attribute Profile (Alpha) Matrix -alphas = sim_alpha_matrix(K) +alphas = sim_attribute_classes(K) +} +\seealso{ +\code{\link[simcdm:sim_subject_attributes]{simcdm::sim_subject_attributes()}} and \code{\link[simcdm:attribute_inv_bijection]{simcdm::attribute_inv_bijection()}} } \author{ James Joseph Balamuta and Steven Andrew Culpepper diff --git a/man/sim_dina_attributes.Rd b/man/sim_dina_attributes.Rd index e1842dd..5024dde 100644 --- a/man/sim_dina_attributes.Rd +++ b/man/sim_dina_attributes.Rd @@ -12,6 +12,10 @@ sim_dina_attributes(alphas, Q) \item{Q}{A \eqn{J} by \eqn{K} \code{matrix} indicating which skills are required for which items.} } +\value{ +The \eqn{\eta} \code{matrix} with dimensions \eqn{N \times J}{N x J} under +the DINA model. +} \description{ Generates a DINA model's \eqn{\eta} matrix based on alphas and the \eqn{\mathbf{Q}} matrix. @@ -58,6 +62,9 @@ dina_items = sim_dina_items(Alphas, Q, ss, gs) # Simulate attribute data under DINA model dina_attributes = sim_dina_attributes(Alphas, Q) } +\seealso{ +\code{\link[simcdm:sim_dina_class]{simcdm::sim_dina_class()}} and \code{\link[simcdm:sim_dina_items]{simcdm::sim_dina_items()}} +} \author{ Steven Andrew Culpepper and James Joseph Balamuta } diff --git a/man/sim_dina_class.Rd b/man/sim_dina_class.Rd index 4c97cfd..0c04d72 100644 --- a/man/sim_dina_class.Rd +++ b/man/sim_dina_class.Rd @@ -24,7 +24,7 @@ the probability of an incorrect response for individuals with all of the required attributes} } \value{ -A dichotomous item matrix +A dichotomous item matrix with dimensions \eqn{N \times J}{N x J}. } \description{ Generate the dichotomous item matrix for a DINA Model. @@ -44,7 +44,7 @@ qbj = c(4, 2, 1, 4, 2, 1, 4, 2, 1, 6, 5, 3, 6, 5, 3, 7, 7, 7) # Fill Q Matrix Q = matrix(, J, K) for (j in seq_len(J)) { - Q[j,] = inv_bijectionvector(K, qbj[j]) + Q[j,] = attribute_inv_bijection(K, qbj[j]) } # Item parm vals @@ -63,13 +63,16 @@ if (rho > 0) { X = Z \%*\% chol(Sig) thvals = matrix(rep(0, K), N, K, byrow = T) Alphas = 1 * (X > thvals) - CLs = Alphas \%*\% bijectionvector(K) + CLs = Alphas \%*\% attribute_bijection(K) } # Simulate data under DINA model ETA = sim_eta_matrix(K, J, Q) Y_sim = sim_dina_class(N, J, CLs, ETA, gs, ss) } +\seealso{ +\code{\link[simcdm:sim_dina_attributes]{simcdm::sim_dina_attributes()}} and \code{\link[simcdm:sim_dina_items]{simcdm::sim_dina_items()}} +} \author{ Steven Andrew Culpepper and James Joseph Balamuta } diff --git a/man/sim_dina_items.Rd b/man/sim_dina_items.Rd index de50cba..78566a6 100644 --- a/man/sim_dina_items.Rd +++ b/man/sim_dina_items.Rd @@ -66,6 +66,9 @@ dina_items = sim_dina_items(Alphas, Q, ss, gs) # Simulate attribute data under DINA model dina_attributes = sim_dina_attributes(Alphas, Q) } +\seealso{ +\code{\link[simcdm:sim_dina_class]{simcdm::sim_dina_class()}} and \code{\link[simcdm:sim_dina_attributes]{simcdm::sim_dina_attributes()}} +} \author{ Steven Andrew Culpepper and James Joseph Balamuta } diff --git a/man/sim_eta_matrix.Rd b/man/sim_eta_matrix.Rd index 189106b..4c992d1 100644 --- a/man/sim_eta_matrix.Rd +++ b/man/sim_eta_matrix.Rd @@ -20,11 +20,15 @@ A \code{mat} with dimensions \eqn{J \times 2^K}{J x 2^K}. Creates the ideal response matrix for each trait } \examples{ +## Simulation Settings ---- + # Fixed Number of Assessment Items for Q J = 18 # Fixed Number of Attributes for Q -K = 3 +K = 3 + +## Pre-specified configuration ---- # Specify Q qbj = c(4, 2, 1, 4, 2, 1, 4, 2, 1, 6, 5, 3, 6, 5, 3, 7, 7, 7) @@ -32,15 +36,24 @@ qbj = c(4, 2, 1, 4, 2, 1, 4, 2, 1, 6, 5, 3, 6, 5, 3, 7, 7, 7) # Fill Q Matrix Q = matrix(, J, K) for (j in seq_len(J)) { - Q[j,] = inv_bijectionvector(K, qbj[j]) + Q[j,] = attribute_inv_bijection(K, qbj[j]) } # Create an eta matrix ETA = sim_eta_matrix(K, J, Q) -# Generate an ETA matrix for a random Q. +## Random generation of Q matrix with ETA matrix ---- -# Create an eta matrix +# Construct a random q matrix Q_sim = sim_q_matrix(J, K) + +# Generate the eta matrix ETA_gen = sim_eta_matrix(K, J, Q_sim) } +\seealso{ +\code{\link[simcdm:sim_q_matrix]{simcdm::sim_q_matrix()}}, \code{\link[simcdm:attribute_bijection]{simcdm::attribute_bijection()}}, and +\code{\link[simcdm:attribute_inv_bijection]{simcdm::attribute_inv_bijection()}} +} +\author{ +Steven Andrew Culpepper and James Joseph Balamuta +} diff --git a/man/sim_q_matrix.Rd b/man/sim_q_matrix.Rd index 3b2ce68..09f39c4 100644 --- a/man/sim_q_matrix.Rd +++ b/man/sim_q_matrix.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/RcppExports.R \name{sim_q_matrix} \alias{sim_q_matrix} -\title{Generate random Q matrix} +\title{Generate a Random Identifiable Q Matrix} \usage{ sim_q_matrix(J, K) } @@ -16,10 +16,20 @@ A dichotomous \code{matrix} for Q. } \description{ Simulates a Q matrix containing three identity matrices after a row -permutation. +permutation that is identifiable. } \examples{ -sim_q_matrix(7, 2) +## Simulate identifiable Q matrices ---- -sim_q_matrix(10, 3) +# 7 items and 2 attributes +q_matrix_j7_k2 = sim_q_matrix(7, 2) + +# 10 items and 3 attributes +q_matrix_j10_k3 = sim_q_matrix(10, 3) +} +\seealso{ +\code{\link[simcdm:attribute_bijection]{simcdm::attribute_bijection()}} and \code{\link[simcdm:attribute_inv_bijection]{simcdm::attribute_inv_bijection()}} +} +\author{ +Steven Andrew Culpepper and James Joseph Balamuta } diff --git a/man/sim_rrum_items.Rd b/man/sim_rrum_items.Rd index 5c91014..adc6990 100644 --- a/man/sim_rrum_items.Rd +++ b/man/sim_rrum_items.Rd @@ -50,7 +50,7 @@ J = 6 # number of items K = 2 # number of attributes # Matrix where rows represent attribute classes -As = sim_alpha_matrix(K) +As = sim_attribute_classes(K) # Latent Class probabilities pis = c(.1, .2, .3, .4) @@ -88,5 +88,5 @@ annual International Meeting of the Psychometric Society, Asheville, North Carolina. } \author{ -Steven Andrew Culpepper and James Joseph Balamuta +Steven Andrew Culpepper, Aaron Hudson, and James Joseph Balamuta } diff --git a/man/sim_subject_attributes.Rd b/man/sim_subject_attributes.Rd new file mode 100644 index 0000000..1dac0b7 --- /dev/null +++ b/man/sim_subject_attributes.Rd @@ -0,0 +1,46 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{sim_subject_attributes} +\alias{sim_subject_attributes} +\title{Simulate Subject Latent Attribute Profiles \eqn{\mathbf{\alpha}_c}} +\usage{ +sim_subject_attributes(N, K, probs = NULL) +} +\arguments{ +\item{N}{Number of Observations} + +\item{K}{Number of Skills} + +\item{probs}{A \code{vector} of probabilities that sum to 1.} +} +\value{ +A \eqn{N} by \eqn{K} \code{matrix} of latent classes +corresponding to entry \eqn{c} of \eqn{pi} based upon +mastery and nonmastery of the \eqn{K} skills. +} +\description{ +Generate a sample from the +\eqn{\mathbf{\alpha}_c = (\alpha_{c1}, \ldots, \alpha_{cK})'} +attribute profile matrix for members of class \eqn{c} such that \eqn{\alpha_{ck}} +is 1 if members of class \eqn{c} possess skill \eqn{k} and zero otherwise. +} +\examples{ +# Define number of subjects and attributes +N = 100 +K = 3 + +# Generate a sample from the Latent Attribute Profile (Alpha) Matrix +# By default, we sample from a uniform distribution weighting of classes. +alphas_builtin = sim_subject_attributes(N, K) + +# Generate a sample using custom probabilities from the +# Latent Attribute Profile (Alpha) Matrix +probs = rep(1 / (2 ^ K), 2 ^ K) +alphas_custom = sim_subject_attributes(N, K, probs) +} +\seealso{ +\code{\link[simcdm:sim_attribute_classes]{simcdm::sim_attribute_classes()}} and \code{\link[simcdm:attribute_inv_bijection]{simcdm::attribute_inv_bijection()}} +} +\author{ +James Joseph Balamuta and Steven Andrew Culpepper +} diff --git a/man/simcdm-package.Rd b/man/simcdm-package.Rd index 2a29da2..98d6871 100644 --- a/man/simcdm-package.Rd +++ b/man/simcdm-package.Rd @@ -12,13 +12,21 @@ Provides efficient R and 'C++' routines to simulate cognitive diagnostic Culpepper and Hudson (2017) , Culpepper (2015) , and de la Torre (2009) . +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/tmsalab/simcdm} + \item Report bugs at \url{https://github.com/tmsalab/simcdm/issues} +} + } \author{ -\strong{Maintainer}: James Joseph Balamuta \email{balamut2@illinois.edu} [copyright holder] +\strong{Maintainer}: James Joseph Balamuta \email{balamut2@illinois.edu} (0000-0003-2826-8458) [copyright holder] Authors: \itemize{ - \item Steven Andrew Culpepper \email{sculpepp@illinois.edu} [copyright holder] + \item Steven Andrew Culpepper \email{sculpepp@illinois.edu} (0000-0003-4226-6176) [copyright holder] } Other contributors: diff --git a/src/Makevars b/src/Makevars index 52105b1..db20cc5 100644 --- a/src/Makevars +++ b/src/Makevars @@ -1,2 +1,8 @@ -PKG_CXXFLAGS = -I../inst/include -PKG_LIBS=$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) +# Enable C++11 +CXX_STD = CXX11 + +# Enable the header file and OpenMP +PKG_CXXFLAGS = -I../inst/include $(SHLIB_OPENMP_CXXFLAGS) + +# Specify the required linking setup +PKG_LIBS=$(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) diff --git a/src/Makevars.win b/src/Makevars.win index 52105b1..db20cc5 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -1,2 +1,8 @@ -PKG_CXXFLAGS = -I../inst/include -PKG_LIBS=$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) +# Enable C++11 +CXX_STD = CXX11 + +# Enable the header file and OpenMP +PKG_CXXFLAGS = -I../inst/include $(SHLIB_OPENMP_CXXFLAGS) + +# Specify the required linking setup +PKG_LIBS=$(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index a33e0a6..44750b5 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -194,21 +194,21 @@ RcppExport SEXP _simcdm_sim_rrum_items(SEXP QSEXP, SEXP rstarSEXP, SEXP pistarSE UNPROTECT(1); return rcpp_result_gen; } -// bijectionvector -arma::vec bijectionvector(unsigned int K); -static SEXP _simcdm_bijectionvector_try(SEXP KSEXP) { +// attribute_bijection +arma::vec attribute_bijection(unsigned int K); +static SEXP _simcdm_attribute_bijection_try(SEXP KSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::traits::input_parameter< unsigned int >::type K(KSEXP); - rcpp_result_gen = Rcpp::wrap(bijectionvector(K)); + rcpp_result_gen = Rcpp::wrap(attribute_bijection(K)); return rcpp_result_gen; END_RCPP_RETURN_ERROR } -RcppExport SEXP _simcdm_bijectionvector(SEXP KSEXP) { +RcppExport SEXP _simcdm_attribute_bijection(SEXP KSEXP) { SEXP rcpp_result_gen; { Rcpp::RNGScope rcpp_rngScope_gen; - rcpp_result_gen = PROTECT(_simcdm_bijectionvector_try(KSEXP)); + rcpp_result_gen = PROTECT(_simcdm_attribute_bijection_try(KSEXP)); } Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); if (rcpp_isInterrupt_gen) { @@ -228,22 +228,22 @@ RcppExport SEXP _simcdm_bijectionvector(SEXP KSEXP) { UNPROTECT(1); return rcpp_result_gen; } -// inv_bijectionvector -arma::vec inv_bijectionvector(unsigned int K, double CL); -static SEXP _simcdm_inv_bijectionvector_try(SEXP KSEXP, SEXP CLSEXP) { +// attribute_inv_bijection +arma::vec attribute_inv_bijection(unsigned int K, double CL); +static SEXP _simcdm_attribute_inv_bijection_try(SEXP KSEXP, SEXP CLSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::traits::input_parameter< unsigned int >::type K(KSEXP); Rcpp::traits::input_parameter< double >::type CL(CLSEXP); - rcpp_result_gen = Rcpp::wrap(inv_bijectionvector(K, CL)); + rcpp_result_gen = Rcpp::wrap(attribute_inv_bijection(K, CL)); return rcpp_result_gen; END_RCPP_RETURN_ERROR } -RcppExport SEXP _simcdm_inv_bijectionvector(SEXP KSEXP, SEXP CLSEXP) { +RcppExport SEXP _simcdm_attribute_inv_bijection(SEXP KSEXP, SEXP CLSEXP) { SEXP rcpp_result_gen; { Rcpp::RNGScope rcpp_rngScope_gen; - rcpp_result_gen = PROTECT(_simcdm_inv_bijectionvector_try(KSEXP, CLSEXP)); + rcpp_result_gen = PROTECT(_simcdm_attribute_inv_bijection_try(KSEXP, CLSEXP)); } Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); if (rcpp_isInterrupt_gen) { @@ -334,21 +334,57 @@ RcppExport SEXP _simcdm_sim_eta_matrix(SEXP KSEXP, SEXP JSEXP, SEXP QSEXP) { UNPROTECT(1); return rcpp_result_gen; } -// sim_alpha_matrix -arma::mat sim_alpha_matrix(int K); -static SEXP _simcdm_sim_alpha_matrix_try(SEXP KSEXP) { +// sim_attribute_classes +arma::mat sim_attribute_classes(int K); +static SEXP _simcdm_sim_attribute_classes_try(SEXP KSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::traits::input_parameter< int >::type K(KSEXP); - rcpp_result_gen = Rcpp::wrap(sim_alpha_matrix(K)); + rcpp_result_gen = Rcpp::wrap(sim_attribute_classes(K)); return rcpp_result_gen; END_RCPP_RETURN_ERROR } -RcppExport SEXP _simcdm_sim_alpha_matrix(SEXP KSEXP) { +RcppExport SEXP _simcdm_sim_attribute_classes(SEXP KSEXP) { SEXP rcpp_result_gen; { Rcpp::RNGScope rcpp_rngScope_gen; - rcpp_result_gen = PROTECT(_simcdm_sim_alpha_matrix_try(KSEXP)); + rcpp_result_gen = PROTECT(_simcdm_sim_attribute_classes_try(KSEXP)); + } + Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); + if (rcpp_isInterrupt_gen) { + UNPROTECT(1); + Rf_onintr(); + } + bool rcpp_isLongjump_gen = Rcpp::internal::isLongjumpSentinel(rcpp_result_gen); + if (rcpp_isLongjump_gen) { + Rcpp::internal::resumeJump(rcpp_result_gen); + } + Rboolean rcpp_isError_gen = Rf_inherits(rcpp_result_gen, "try-error"); + if (rcpp_isError_gen) { + SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); + UNPROTECT(1); + Rf_error(CHAR(rcpp_msgSEXP_gen)); + } + UNPROTECT(1); + return rcpp_result_gen; +} +// sim_subject_attributes +arma::mat sim_subject_attributes(int N, int K, Rcpp::Nullable probs); +static SEXP _simcdm_sim_subject_attributes_try(SEXP NSEXP, SEXP KSEXP, SEXP probsSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::traits::input_parameter< int >::type N(NSEXP); + Rcpp::traits::input_parameter< int >::type K(KSEXP); + Rcpp::traits::input_parameter< Rcpp::Nullable >::type probs(probsSEXP); + rcpp_result_gen = Rcpp::wrap(sim_subject_attributes(N, K, probs)); + return rcpp_result_gen; +END_RCPP_RETURN_ERROR +} +RcppExport SEXP _simcdm_sim_subject_attributes(SEXP NSEXP, SEXP KSEXP, SEXP probsSEXP) { + SEXP rcpp_result_gen; + { + Rcpp::RNGScope rcpp_rngScope_gen; + rcpp_result_gen = PROTECT(_simcdm_sim_subject_attributes_try(NSEXP, KSEXP, probsSEXP)); } Rboolean rcpp_isInterrupt_gen = Rf_inherits(rcpp_result_gen, "interrupted-error"); if (rcpp_isInterrupt_gen) { @@ -378,11 +414,12 @@ static int _simcdm_RcppExport_validate(const char* sig) { signatures.insert("arma::mat(*sim_dina_items)(const arma::mat&,const arma::mat&,const arma::vec&,const arma::vec&)"); signatures.insert("arma::mat(*sim_rrum_main)(const arma::mat&,const arma::mat&,const arma::vec&,const arma::mat&)"); signatures.insert("arma::mat(*sim_rrum_items)(const arma::mat&,const arma::mat&,const arma::vec&,const arma::mat&)"); - signatures.insert("arma::vec(*bijectionvector)(unsigned int)"); - signatures.insert("arma::vec(*inv_bijectionvector)(unsigned int,double)"); + signatures.insert("arma::vec(*attribute_bijection)(unsigned int)"); + signatures.insert("arma::vec(*attribute_inv_bijection)(unsigned int,double)"); signatures.insert("arma::mat(*sim_q_matrix)(unsigned int,unsigned int)"); signatures.insert("arma::mat(*sim_eta_matrix)(unsigned int,unsigned int,const arma::mat&)"); - signatures.insert("arma::mat(*sim_alpha_matrix)(int)"); + signatures.insert("arma::mat(*sim_attribute_classes)(int)"); + signatures.insert("arma::mat(*sim_subject_attributes)(int,int,Rcpp::Nullable)"); } return signatures.find(sig) != signatures.end(); } @@ -394,11 +431,12 @@ RcppExport SEXP _simcdm_RcppExport_registerCCallable() { R_RegisterCCallable("simcdm", "_simcdm_sim_dina_items", (DL_FUNC)_simcdm_sim_dina_items_try); R_RegisterCCallable("simcdm", "_simcdm_sim_rrum_main", (DL_FUNC)_simcdm_sim_rrum_main_try); R_RegisterCCallable("simcdm", "_simcdm_sim_rrum_items", (DL_FUNC)_simcdm_sim_rrum_items_try); - R_RegisterCCallable("simcdm", "_simcdm_bijectionvector", (DL_FUNC)_simcdm_bijectionvector_try); - R_RegisterCCallable("simcdm", "_simcdm_inv_bijectionvector", (DL_FUNC)_simcdm_inv_bijectionvector_try); + R_RegisterCCallable("simcdm", "_simcdm_attribute_bijection", (DL_FUNC)_simcdm_attribute_bijection_try); + R_RegisterCCallable("simcdm", "_simcdm_attribute_inv_bijection", (DL_FUNC)_simcdm_attribute_inv_bijection_try); R_RegisterCCallable("simcdm", "_simcdm_sim_q_matrix", (DL_FUNC)_simcdm_sim_q_matrix_try); R_RegisterCCallable("simcdm", "_simcdm_sim_eta_matrix", (DL_FUNC)_simcdm_sim_eta_matrix_try); - R_RegisterCCallable("simcdm", "_simcdm_sim_alpha_matrix", (DL_FUNC)_simcdm_sim_alpha_matrix_try); + R_RegisterCCallable("simcdm", "_simcdm_sim_attribute_classes", (DL_FUNC)_simcdm_sim_attribute_classes_try); + R_RegisterCCallable("simcdm", "_simcdm_sim_subject_attributes", (DL_FUNC)_simcdm_sim_subject_attributes_try); R_RegisterCCallable("simcdm", "_simcdm_RcppExport_validate", (DL_FUNC)_simcdm_RcppExport_validate); return R_NilValue; } @@ -409,11 +447,12 @@ static const R_CallMethodDef CallEntries[] = { {"_simcdm_sim_dina_items", (DL_FUNC) &_simcdm_sim_dina_items, 4}, {"_simcdm_sim_rrum_main", (DL_FUNC) &_simcdm_sim_rrum_main, 4}, {"_simcdm_sim_rrum_items", (DL_FUNC) &_simcdm_sim_rrum_items, 4}, - {"_simcdm_bijectionvector", (DL_FUNC) &_simcdm_bijectionvector, 1}, - {"_simcdm_inv_bijectionvector", (DL_FUNC) &_simcdm_inv_bijectionvector, 2}, + {"_simcdm_attribute_bijection", (DL_FUNC) &_simcdm_attribute_bijection, 1}, + {"_simcdm_attribute_inv_bijection", (DL_FUNC) &_simcdm_attribute_inv_bijection, 2}, {"_simcdm_sim_q_matrix", (DL_FUNC) &_simcdm_sim_q_matrix, 2}, {"_simcdm_sim_eta_matrix", (DL_FUNC) &_simcdm_sim_eta_matrix, 3}, - {"_simcdm_sim_alpha_matrix", (DL_FUNC) &_simcdm_sim_alpha_matrix, 1}, + {"_simcdm_sim_attribute_classes", (DL_FUNC) &_simcdm_sim_attribute_classes, 1}, + {"_simcdm_sim_subject_attributes", (DL_FUNC) &_simcdm_sim_subject_attributes, 3}, {"_simcdm_RcppExport_registerCCallable", (DL_FUNC) &_simcdm_RcppExport_registerCCallable, 0}, {NULL, NULL, 0} }; diff --git a/src/sim_dina.cpp b/src/sim_dina.cpp index 7f139cb..52737ec 100644 --- a/src/sim_dina.cpp +++ b/src/sim_dina.cpp @@ -17,10 +17,17 @@ //' the probability of an incorrect response for individuals with //' all of the required attributes //' -//' @return A dichotomous item matrix -//' @author Steven Andrew Culpepper and James Joseph Balamuta -//' @template sim-dina-class-example +//' @return +//' A dichotomous item matrix with dimensions \eqn{N \times J}{N x J}. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::sim_dina_attributes()] and [simcdm::sim_dina_items()] +//' //' @export +//' @template sim-dina-class-example // [[Rcpp::export]] arma::mat sim_dina_class(unsigned int N, unsigned int J, const arma::vec &CLASS, const arma::mat &ETA, const arma::vec &gs, @@ -43,10 +50,21 @@ arma::mat sim_dina_class(unsigned int N, unsigned int J, const arma::vec &CLASS, //' //' Generates a DINA model's \eqn{\eta} matrix based on alphas and //' the \eqn{\mathbf{Q}} matrix. +//' //' @inheritParams sim_dina_items -//' @author Steven Andrew Culpepper and James Joseph Balamuta -//' @template sim-dina-example-body +//' +//' @return +//' The \eqn{\eta} `matrix` with dimensions \eqn{N \times J}{N x J} under +//' the DINA model. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::sim_dina_class()] and [simcdm::sim_dina_items()] +//' //' @export +//' @template sim-dina-example-body // [[Rcpp::export]] arma::mat sim_dina_attributes(const arma::mat &alphas, const arma::mat &Q) { @@ -81,10 +99,17 @@ arma::mat sim_dina_attributes(const arma::mat &alphas, const arma::mat &Q) //' @param ss A \eqn{J} `vector` of item slipping parameters. //' @param gs A \eqn{J} `vector` of item guessing parameters. //' -//' @return A \eqn{N} by \eqn{J} `matrix` of responses from the DINA model. -//' @author Steven Andrew Culpepper and James Joseph Balamuta -//' @template sim-dina-example-body +//' @return +//' A \eqn{N} by \eqn{J} `matrix` of responses from the DINA model. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::sim_dina_class()] and [simcdm::sim_dina_attributes()] +//' //' @export +//' @template sim-dina-example-body // [[Rcpp::export]] arma::mat sim_dina_items(const arma::mat &alphas, const arma::mat &Q, const arma::vec &ss, const arma::vec &gs) diff --git a/src/sim_rrum.cpp b/src/sim_rrum.cpp index e3d13e7..87a279e 100644 --- a/src/sim_rrum.cpp +++ b/src/sim_rrum.cpp @@ -64,11 +64,12 @@ arma::mat sim_rrum_main(const arma::mat &Q, const arma::mat &rstar, //' the number of attributes. An entry of 1 indicates individual //' \eqn{i} has attained attribute \eqn{k}. An entry of 0 //' indicates the attribute has not been attained. -//' //' @return Y A `matrix` with \eqn{N} rows and \eqn{J} columns indicating //' the indviduals' responses to each of the items, where \eqn{J} //' represents the number of items. -//' @author Steven Andrew Culpepper and James Joseph Balamuta +//' @author +//' Steven Andrew Culpepper, Aaron Hudson, and James Joseph Balamuta +//' //' @export //' @template rrum-example //' @template rrum-references diff --git a/src/utilities.cpp b/src/utilities.cpp index 641e01e..24d5045 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -1,19 +1,30 @@ #include +#include // [[Rcpp::interfaces(r, cpp)]] -//' Bijection Vector +//' Constructs Unique Attribute Pattern Map //' -//' Computes the powers of 2 from \eqn{0} up to \eqn{K - 1}. +//' Computes the powers of 2 from \eqn{0} up to \eqn{K - 1} for +//' \eqn{K}-dimensional attribute pattern. +//' //' @param K Number of Attributes. -//' @return A \code{vec} with length \eqn{K} detailing the power's of 2. -//' @examples -//' -//' bijectionvector(3) -//' +//' +//' @return +//' A \code{vec} with length \eqn{K} detailing the power's of 2. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::attribute_inv_bijection()] +//' //' @export +//' @examples +//' ## Construct an attribute bijection ---- +//' biject = attribute_bijection(3) // [[Rcpp::export]] -arma::vec bijectionvector(unsigned int K) +arma::vec attribute_bijection(unsigned int K) { arma::vec vv(K); for (unsigned int i = 0; i < K; ++i) { @@ -24,20 +35,29 @@ arma::vec bijectionvector(unsigned int K) //' Perform an Inverse Bijection of an Integer to Attribute Pattern //' -//' Convert integer between \eqn{0} and \eqn{2^{K-1}} to +//' Convert an integer between \eqn{0} and \eqn{2^{K-1}} to //' \eqn{K}-dimensional attribute pattern. //' //' @param CL An `integer` between \eqn{0} and \eqn{2^{K-1}} -//' @inheritParams bijectionvector -//' @return A \eqn{K}-dimensional vector with an attribute pattern corresponding +//' @inheritParams attribute_bijection +//' +//' @return +//' A \eqn{K}-dimensional vector with an attribute pattern corresponding //' to `CL`. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::attribute_bijection()] +//' //' @export -//' //' @examples -//' inv_bijectionvector(5, 1) -//' inv_bijectionvector(5, 2) +//' ## Construct an attribute inversion bijection ---- +//' inv_biject1 = attribute_inv_bijection(5, 1) +//' inv_biject2 = attribute_inv_bijection(5, 2) // [[Rcpp::export]] -arma::vec inv_bijectionvector(unsigned int K, double CL) +arma::vec attribute_inv_bijection(unsigned int K, double CL) { arma::vec alpha(K); @@ -50,20 +70,32 @@ arma::vec inv_bijectionvector(unsigned int K, double CL) return alpha; } -//' Generate random Q matrix +//' Generate a Random Identifiable Q Matrix //' //' Simulates a Q matrix containing three identity matrices after a row -//' permutation. +//' permutation that is identifiable. //' //' @param J Number of Items //' @param K Number of Attributes //' -//' @return A dichotomous \code{matrix} for Q. -//' @examples -//' sim_q_matrix(7, 2) +//' @return +//' A dichotomous \code{matrix} for Q. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::attribute_bijection()] and [simcdm::attribute_inv_bijection()] //' -//' sim_q_matrix(10, 3) //' @export +//' @examples +//' ## Simulate identifiable Q matrices ---- +//' +//' # 7 items and 2 attributes +//' q_matrix_j7_k2 = sim_q_matrix(7, 2) +//' +//' # 10 items and 3 attributes +//' q_matrix_j10_k3 = sim_q_matrix(10, 3) // [[Rcpp::export]] arma::mat sim_q_matrix(unsigned int J, unsigned int K) { @@ -76,7 +108,7 @@ arma::mat sim_q_matrix(unsigned int J, unsigned int K) unsigned int nClass = pow(2, K); // Form a Bijection - arma::vec vv = bijectionvector(K); + arma::vec vv = attribute_bijection(K); // Fill Q bijection vector arma::vec Q_biject(J); @@ -95,7 +127,7 @@ arma::mat sim_q_matrix(unsigned int J, unsigned int K) // Create Q Matrix arma::mat Q(J, K); for (unsigned int j = 0; j < J; ++j) { - arma::vec qj = inv_bijectionvector(K, Q_biject(j)); + arma::vec qj = attribute_inv_bijection(K, Q_biject(j)); Q.row(j) = qj.t(); } @@ -109,15 +141,28 @@ arma::mat sim_q_matrix(unsigned int J, unsigned int K) //' @param K Number of Attribute Levels //' @param J Number of Assessment Items //' @param Q Q Matrix with dimensions \eqn{K \times J}{K x J}. -//' @return A `mat` with dimensions \eqn{J \times 2^K}{J x 2^K}. +//' +//' @return +//' A `mat` with dimensions \eqn{J \times 2^K}{J x 2^K}. +//' +//' @author +//' Steven Andrew Culpepper and James Joseph Balamuta +//' +//' @seealso +//' [simcdm::sim_q_matrix()], [simcdm::attribute_bijection()], and +//' [simcdm::attribute_inv_bijection()] +//' //' @export -//' //' @examples +//' ## Simulation Settings ---- +//' //' # Fixed Number of Assessment Items for Q //' J = 18 //' //' # Fixed Number of Attributes for Q -//' K = 3 +//' K = 3 +//' +//' ## Pre-specified configuration ---- //' //' # Specify Q //' qbj = c(4, 2, 1, 4, 2, 1, 4, 2, 1, 6, 5, 3, 6, 5, 3, 7, 7, 7) @@ -125,16 +170,18 @@ arma::mat sim_q_matrix(unsigned int J, unsigned int K) //' # Fill Q Matrix //' Q = matrix(, J, K) //' for (j in seq_len(J)) { -//' Q[j,] = inv_bijectionvector(K, qbj[j]) +//' Q[j,] = attribute_inv_bijection(K, qbj[j]) //' } //' //' # Create an eta matrix //' ETA = sim_eta_matrix(K, J, Q) //' -//' # Generate an ETA matrix for a random Q. +//' ## Random generation of Q matrix with ETA matrix ---- //' -//' # Create an eta matrix +//' # Construct a random q matrix //' Q_sim = sim_q_matrix(J, K) +//' +//' # Generate the eta matrix //' ETA_gen = sim_eta_matrix(K, J, Q_sim) // [[Rcpp::export]] arma::mat sim_eta_matrix(unsigned int K, unsigned int J, const arma::mat &Q) @@ -144,7 +191,7 @@ arma::mat sim_eta_matrix(unsigned int K, unsigned int J, const arma::mat &Q) arma::mat ETA(J, nClass); for (unsigned int cc = 0; cc < nClass; ++cc) { - arma::vec alpha_c = inv_bijectionvector(K, cc); + arma::vec alpha_c = attribute_inv_bijection(K, cc); for (unsigned int j = 0; j < J; ++j) { arma::rowvec qj = Q.row(j); @@ -157,38 +204,122 @@ arma::mat sim_eta_matrix(unsigned int K, unsigned int J, const arma::mat &Q) return ETA; } -//' Simulate the Latent Attribute Profile Matrix \eqn{\mathbf{\alpha}_c} +//' Simulate all the Latent Attribute Profile \eqn{\mathbf{\alpha}_c} in Matrix form //' //' Generate the \eqn{\mathbf{\alpha}_c = (\alpha_{c1}, \ldots, \alpha_{cK})'} //' attribute profile matrix for members of class \eqn{c} such that \eqn{\alpha_{ck}} //' is 1 if members of class \eqn{c} possess skill \eqn{k} and zero otherwise. //' -//' @param K Number of Skills +//' @param K Number of Attributes //' -//' @return A \eqn{2^K} by \eqn{K} `matrix` of latent classes +//' @return +//' A \eqn{2^K} by \eqn{K} `matrix` of latent classes //' corresponding to entry \eqn{c} of \eqn{pi} based upon //' mastery and nonmastery of the \eqn{K} skills. //' -//' @author James Joseph Balamuta and Steven Andrew Culpepper +//' @author +//' James Joseph Balamuta and Steven Andrew Culpepper //' -//' @export +//' @seealso +//' [simcdm::sim_subject_attributes()] and [simcdm::attribute_inv_bijection()] //' +//' @export //' @examples -//' # Define test parameters and traits +//' ## Simulate Attribute Class Matrix ---- +//' +//' # Define number of attributes //' K = 3 //' //' # Generate an Latent Attribute Profile (Alpha) Matrix -//' alphas = sim_alpha_matrix(K) +//' alphas = sim_attribute_classes(K) // [[Rcpp::export]] -arma::mat sim_alpha_matrix(int K) { +arma::mat sim_attribute_classes(int K) { // Modified version of ETAMatrix double nClass = pow(2, K); arma::mat alpha_matrix(nClass, K); for(unsigned int cc = 0; cc < nClass; cc++){ - alpha_matrix.row(cc) = inv_bijectionvector(K, cc).t(); + alpha_matrix.row(cc) = attribute_inv_bijection(K, cc).t(); } return alpha_matrix; +} + +//' Simulate Subject Latent Attribute Profiles \eqn{\mathbf{\alpha}_c} +//' +//' Generate a sample from the +//' \eqn{\mathbf{\alpha}_c = (\alpha_{c1}, \ldots, \alpha_{cK})'} +//' attribute profile matrix for members of class \eqn{c} such that \eqn{\alpha_{ck}} +//' is 1 if members of class \eqn{c} possess skill \eqn{k} and zero otherwise. +//' +//' @param N Number of Observations +//' @param K Number of Skills +//' @param probs A `vector` of probabilities that sum to 1. +//' +//' @return +//' A \eqn{N} by \eqn{K} `matrix` of latent classes +//' corresponding to entry \eqn{c} of \eqn{pi} based upon +//' mastery and nonmastery of the \eqn{K} skills. +//' +//' @author +//' James Joseph Balamuta and Steven Andrew Culpepper +//' +//' @seealso +//' [simcdm::sim_attribute_classes()] and [simcdm::attribute_inv_bijection()] +//' +//' @export +//' @examples +//' # Define number of subjects and attributes +//' N = 100 +//' K = 3 +//' +//' # Generate a sample from the Latent Attribute Profile (Alpha) Matrix +//' # By default, we sample from a uniform distribution weighting of classes. +//' alphas_builtin = sim_subject_attributes(N, K) +//' +//' # Generate a sample using custom probabilities from the +//' # Latent Attribute Profile (Alpha) Matrix +//' probs = rep(1 / (2 ^ K), 2 ^ K) +//' alphas_custom = sim_subject_attributes(N, K, probs) +// [[Rcpp::export]] +arma::mat sim_subject_attributes(int N, int K, + Rcpp::Nullable probs = R_NilValue) { + // Modified version of ETAMatrix + + // Compute the number of attributes + double nClass = pow(2, K); + + // Nullable trick ---- + arma::vec probs_; + + // Check if probs is present + if (probs.isNotNull()) { + + // Retrieve probabilities (costly) + probs_ = Rcpp::as(probs); + + // Verify length is okay. + if (probs_.n_elem != (int)nClass) { + Rcpp::stop("`probs` must have %s elements instead of %s.", + nClass, probs_.size()); + } + } else { + probs_.set_size(nClass); + probs_.fill(1.0/nClass); + } + + // --- Profile Matrix + + // Grab the attribute matrix + arma::mat attributes = sim_attribute_classes(K); + + // Generate indices + arma::uvec idx = arma::linspace(0, nClass - 1, nClass); + + // Update index + idx = Rcpp::RcppArmadillo::sample_main(idx, N, true, probs_); + + // Retrieve and return profiles + return attributes.rows(idx); } \ No newline at end of file diff --git a/tests/testthat/test-bijections.R b/tests/testthat/test-bijections.R index 4e0a00d..6d4699a 100644 --- a/tests/testthat/test-bijections.R +++ b/tests/testthat/test-bijections.R @@ -1,12 +1,12 @@ -context("test-bijections") +context("test-attribute bijections") -test_that("valid bijectionvector", { +test_that("valid attribute_bijection", { bijection_test = matrix( 2^((3-1):0) ) - expect_equal(bijectionvector(3), bijection_test) + expect_equal(attribute_bijection(3), bijection_test) }) -test_that("valid inv_bijectionvector", { +test_that("valid attribute_inv_bijection", { inv_bijection_test = function(K, CL) { alpha = rep(NA, K) @@ -20,10 +20,10 @@ test_that("valid inv_bijectionvector", { matrix(alpha) } - expect_equal(inv_bijectionvector(3, 0), inv_bijection_test(3, 0)) + expect_equal(attribute_inv_bijection(3, 0), inv_bijection_test(3, 0)) - expect_equal(inv_bijectionvector(4, 1), inv_bijection_test(4, 1)) + expect_equal(attribute_inv_bijection(4, 1), inv_bijection_test(4, 1)) - expect_equal(inv_bijectionvector(5, 2), inv_bijection_test(5, 2)) + expect_equal(attribute_inv_bijection(5, 2), inv_bijection_test(5, 2)) }) diff --git a/tests/testthat/test-matrix-types.R b/tests/testthat/test-matrix-types.R index c948d4c..07a8fea 100644 --- a/tests/testthat/test-matrix-types.R +++ b/tests/testthat/test-matrix-types.R @@ -4,22 +4,24 @@ test_that("Generate alpha matrix (pi references)", { # Old, r-specific pi mapping function pi_reference = function(K) { - biject.vector = bijectionvector(K) - As = as.matrix(expand.grid(rep(list(c(0,1)), K))) - a = As%*%biject.vector - As = As[a+1,] + biject.vector = attribute_bijection(K) + As = as.matrix( + expand.grid( rep( list(c(0, 1)), K) ) + ) + a = As %*% biject.vector + As = As[a + 1,] return(As) } # Check equality - expect_equal(sim_alpha_matrix(2), pi_reference(2), check.attributes = FALSE, + expect_equal(sim_attribute_classes(2), pi_reference(2), check.attributes = FALSE, info = "Verify latent class mapping is correct.") # Check equality - expect_equal(sim_alpha_matrix(5), pi_reference(5), check.attributes = FALSE, + expect_equal(sim_attribute_classes(5), pi_reference(5), check.attributes = FALSE, info = "Verify latent class mapping is correct.") # Check equality - expect_equal(sim_alpha_matrix(8), pi_reference(8), check.attributes = FALSE, + expect_equal(sim_attribute_classes(8), pi_reference(8), check.attributes = FALSE, info = "Verify latent class mapping is correct.") }) diff --git a/vignettes/.gitignore b/vignettes/.gitignore new file mode 100644 index 0000000..097b241 --- /dev/null +++ b/vignettes/.gitignore @@ -0,0 +1,2 @@ +*.html +*.R diff --git a/vignettes/overview-simcdm.Rmd b/vignettes/overview-simcdm.Rmd new file mode 100644 index 0000000..c8cbd10 --- /dev/null +++ b/vignettes/overview-simcdm.Rmd @@ -0,0 +1,186 @@ +--- +title: "Overview of `simcdm`" +author: "James Joseph Balamuta" +date: "`r Sys.Date()`" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Overview of simcdm} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +# Overview + +Within this document, we highlight the different features of the `simcdm` package +as it relates to simulating cognitive diagnostic modeling data. + +## Notation + +For consistency, we aim to use the following notation. + +Denoting individuals: + +- $N$ is the total number of individuals taking the assessment. +- $i$ is the current individual. + +Denoting items: + +- $J$ is the total number of items on the assessment. +- $j$ is the current item +- $Y_{ij}$ is the observed binary response for individual $i$ ($1\leq i \leq N$) to item $j$ ($1\leq j\leq J$). +- $s_j$ is the probability of slipping on item $j$. +- $g_j$ is the probability of guessing on item $j$. + +Denoting attributes: + +- $K$ is the total number of attributes for the assessment item. +- $k$ is the current attribute. +- $\boldsymbol\alpha_i=\left(\alpha_{i1},\dots,\alpha_{iK}\right)^\prime$ + where $\boldsymbol\alpha_i\in \left\{0,1\right\}^K$ and $\alpha_{ik}$ is + the latent binary attribute for individual $i$ on attribute $k$ ($1\leq k\leq K$). + +Denoting the skill/attribute "Q" matrix: + +- $\boldsymbol q_{j}=\left(q_{j1},\dots,q_{jK}\right)^\prime$ be the + $j$th row of $\boldsymbol Q$ such that $q_{jk}=1$ if + attribute $k$ is required for item $j$ and zero otherwise. + +# Usage + +To use `simcdm`, please load the package. + +```{r} +library(simcdm) +``` + +## Matrix Simulation + +Simulations within this section are done underneath the following settings. + +```{r} +# Set a seed for reproducibility +set.seed(888) + +# Setup Parameters +N = 15 # Number of Examinees / Subjects +J = 10 # Number of Items +K = 2 # Number of Skills / Attributes +``` + +### Identifiable Q Matrix Simulation + +Simulate an identifiable $Q$ matrix ($J$ items by $K$ skills). + +```{r} +Q = sim_q_matrix(J, K) +Q +``` + +### $\eta$ Matrix Simulation + +Create the ideal response matrix for each trait ($J$ items by $2^K$ latent classes). + +```{r} +eta = sim_eta_matrix(K, J, Q) +eta +``` + +### Attribute profile simulation + +Generate latent attribute profile classes ($2^K$ latent classes by $K$ skills). + +```{r} +class_alphas = sim_attribute_classes(K) +class_alphas +``` + +Generate latent attribute profile class for each subject ($N$ subjects by $K$ skills). + +```{r} +subject_alphas = sim_subject_attributes(N, K) +subject_alphas + +# Equivalent to: +# subject_alphas = class_alphas[sample(2 ^ K, N, replace = TRUE),] +``` + +### DINA Simulation + +Simulations within this section are done underneath the following settings. + +```{r} +# Set a seed for reproducibility +set.seed(888) + +# Setup Parameters +N = 15 # Number of Examinees / Subjects +J = 10 # Number of Items +K = 2 # Number of Skills / Attributes + +# Assign slipping and guessing values for each item +ss = gs = rep(.2, J) + +# Simulate identifiable Q matrix +Q = sim_q_matrix(J, K) + +# Simulate subject attributes +subject_alphas = sim_subject_attributes(N, K) +``` + +### DINA Item Simulation + +Simulate item data, $Y$, under DINA model ($N$ by $J$) + +```{r} +items_dina = sim_dina_items(subject_alphas, Q, ss, gs) +items_dina +``` + +### DINA Attribute Simulation + +Simulate attribute data under DINA model ($N$ by $J$) + +```{r} +attributes = sim_dina_attributes(subject_alphas, Q) +attributes +``` + +## rRUM Simulation + +The rRUM simulations are done using the following settings. + +```{r} +# Set a seed for reproducibility +set.seed(888) + +# Setup Parameters +N = 15 # Number of Examinees / Subjects +J = 10 # Number of Items +K = 2 # Number of Skills / Attributes + +# The probabilities of answering each item correctly for individuals +# who do not lack any required attribute +pistar = rep(.9, J) + +# Penalties for failing to have each of the required attributes +rstar = .5 * Q + +# Latent Class Probabilities +pis = c(.1, .2, .3, .4) + +# Generate latent attribute profile with custom probability (N subjects by K skills) +subject_alphas = sim_subject_attributes(N, K, prob = pis) + +# Equivalent to: +# class_alphas = sim_attribute_classes(K) +# subject_alphas = class_alphas[sample(2 ^ K, N, replace = TRUE, prob = pis),] +``` + +### Simulate rRUM items + +Simulate rRUM item data $Y$ ($N$ by $J$) + +```{r} +rrum_items = sim_rrum_items(Q, rstar, pistar, subject_alphas) +rrum_items +``` diff --git a/vignettes/simcdm-in-packages.Rmd b/vignettes/simcdm-in-packages.Rmd new file mode 100644 index 0000000..bd0fd89 --- /dev/null +++ b/vignettes/simcdm-in-packages.Rmd @@ -0,0 +1,89 @@ +--- +title: "Using `simcdm` in R packages" +author: "James Joseph Balamuta" +date: "`r Sys.Date()`" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Using simcdm in R Packages} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +# Package usage + +The design of `simcdm` allows the package to be included in other _R_ packages +using either the _R_ or _C++_ functions. The next section details provides +with how to incorporate either the _R_ or _C++_ functions into a new _R_ +package or standalone _C++_ file. + +Note, if you are not familiar with compiled code in _R_ please +feel free to use the traditional way to import the _R_ functions. + +## _R_ Package Usage + +To use `simcdm`'s _R_ functions **only** in your own _R_ package, modify +the package's `DESCRIPTION` file by adding an imports declaration. + +```bash +Imports: simcdm +``` + +Inside of the package's `NAMESPACE` file, make sure to use: + +```bash +import(simcdm) +``` + +If you are using `roxygen2` to manage the packages `NAMESPACE` file, add +the following tag and re-run the `roxygenize()` function. + +```bash +#' @import simcdm +``` + +## _C++_ Usage + + +### _C++_ Standalone Usage + +Within a _C++_ file in `src/`, then add: + +```cpp +#include +#include + +// [[Rcpp::depends(simcdm, RcppArmadillo)]] + +// [[Rcpp::export]] +arma::mat example_dina_sim(const arma::mat &alphas, const arma::mat &Q, + const arma::vec &ss, const arma::vec &gs) { + + arma::mat dina_items = simcdm::sim_dina_items(alphas, Q, ss, gs); + + return dina_items; +} +``` + +### _C++_ Package + +To use _C++_ functions available in `simcdm` within your R package, +modify your package's `DESCRIPTION` file by adding: + + LinkingTo: Rcpp, RcppArmadillo (>= 0.9.200), simcdm + Imports: + Rcpp (>= 1.0.0) + +Reference the simulation functions using `simcdm` namespace like so: + +```cpp +#include + +// [[Rcpp::export]] +arma::mat example_rrum_sim(const arma::mat &Q, const arma::mat &rstar, + const arma::vec &pistar, const arma::mat &alpha) { + + arma::mat rrum_items = simcdm::sim_rrum_items(Q, rstar, pistar, alpha); + + return rrum_items; +} +```