# Introduction to conquestr

#### Dan Cloney

#### 2024-01-05

conquestr has three main functions:

- ConQuestCall: calls ‘ACER ConQuest’ in a terminal and runs syntax
- ConQuestSys: reads and returns ‘ACER ConQuest’ system files as an R object. For example, this provides access to parameter estimates, abilities, and raw data.
- ConQuestRout (and plotRout): reads ‘ACER ConQuest’ plot objects (see the command plot) and creates plots in R via generic functions and dispatch.

These functions allows users to include ‘ACER ConQuest’ within their R workflow. This is particularly useful for users of the Mac OS X version (and Windows console) version of ‘ACER ConQuest’ which does not support ploting.

This vignette demonstrates how to use the package built-in demonstration files to:

- Call ‘ACER ConQuest’ and run a syntax file
- Read in a system file and access data objects

## Call ConQuest and run a syntax file

First, ensure you have the most current version of ConQuest. Version > 5.17.4 is required. If you are unsure, check ConQuest on the ACER Shop. You will also need to install the conquestr library:

    install.packages("conquestr")
    library("conquestr")

You must pass the `ConQuestCall` function at least two pieces of information: the install location of ConQuest and a valid syntax file. conquestr has included syntax files that can be used to run a model and test other package functions. A default syntax file will be called is you do not explicitly provide one. conquestr will search for a valid installation of ‘ACER ConQuest’ unless the executable is explicitly declared. The search locations are (in order):

- The default install location (Windows:`%ProgramFiles%\ACER ConQuest\ConQuestConsole.exe` and Mac OS X: `/Applications/ConQuest/ConQuest`).
- The Program Files folder on Windows, and the Application folder on Mac OS X
- The current user’s Desktop

    # if you don't provide a syntax file, using the argumenmt `cqc=`, then the in-built demo syntax file will be run.
    ConQuestCall()

    # the following output is produced:

    ConQuest build: Mar 10 2021
    <TYPE> Version
    This version expires <DATE>
    submit <PATH>conquestr/extdata/conquestabout.cqc;
    =>dir;
    <PATH>
    =>about;
    Developed by
        Australian Council for Educational Research
        University of California,Berkeley

    Your key: <KEY>
    Expires: <DATE>

    <TYPE> Build:  <DATE>
    Version: 5.17.4

    Programmers
        Ray Adams,Margaret Wu,Greg Macaskill,Sam Haldane,Xiao Xun Sun,Dan Cloney
    End of Program

When you use `ConQuestCall` to call ‘ACER ConQuest’ and run a syntax file, some options are set by default. The same options can be set within ‘ACER ConQuest’ by using the `set` command (`set progress = yes, exit_on_error = yes, storecommands = yes, warnings = no;` which is syntactically the same as using the helper function `set conquestr = true;`). WARNING - this will make it easy to overwrite output as you will not be prompted or warned. To turn off these settings your syntax file must explicitly change these using the `set` command. For more information see the set command.

When calling ‘ACER ConQuest’ from R, the ConQuest working directory will default to the current R working directory. This makes it easy to write portable syntax using relative paths. If you need ‘ACER ConQuest’ to use a different working directory, set it in your syntax file.

The next example runs a small analysis and creates a system file that is read into the R object `myExSys`.

    # set up
    oldWd <- getwd()
    myTmpDir <- tempdir()
    setwd(myTmpDir)
    file.copy(from = c(
      system.file("extdata", "ex1.cqc", package = "conquestr"),
      system.file("extdata", "ex1.dat", package = "conquestr"),
      system.file("extdata", "mysysfile.cqs", package = "conquestr")
      ), to = myTmpDir)
    #> [1] TRUE TRUE TRUE

    # run ConQuest
    # ConQuestCall is not run here, as it requires a local install of ConQuest
    # ConQuestCall(cqc = file.path(myTmpDir, "ex1.cqc"), stdout = NULL) # searches for valid install of CQ
    myExSys <- ConQuestSys(myCqs = file.path(myTmpDir, "mysysfile.cqs"))

    # see the content of the sysfile
    str(myExSys)
    #> List of 211
    #>  $ Compressed             : chr "uncompressed"
    #>  $ builddate              : chr "Aug 24 2023"
    #>  $ writedate              : chr "Mon Aug 28 09:35:51 2023\n"
    #>  $ cqs_version            : int 26
    #>  $ gNCases                :List of 11
    #>   ..$ : num 1000
    #>   ..$ : num 1000
    #>   ..$ : num 1000
    #>   ..$ : num 1000
    #>   ..$ : num 999
    #>   ..$ : num 75
    #>   ..$ : num 925
    #>   ..$ : num 1000
    #>   ..$ : num 999
    #>   ..$ : num 925
    #>   ..$ : num 1000
    #>  $ gNDim                  : int 1
    #>  $ gNGins                 : int 12
    #>  $ gNPlausiblesEstimate   : int 5
    #>  $ gMLEExist              : logi TRUE
    #>  $ gWLEExist              : logi TRUE
    #>  $ gEAPExist              : logi TRUE
    #>  $ gPlausibleExist        : logi TRUE
    #>  $ gSystemMissing         : num -1.8e+308
    #>  $ gApplyFilter           : logi FALSE
    #>  $ gFilter                :List of 4
    #>   ..$ String : logi [1, 1] NA
    #>   ..$ Items  : int 0
    #>   ..$ Columns: int 0
    #>   ..$ Size   : int 0
    #>  $ gBeta                  : num [1, 1] 0
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gOldBeta               : num [1, 1] 0
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gBestBeta              : num [1, 1] 0
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gXsi                   : num [1:12, 1] -0.704 -1.251 -1.092 -0.231 0.111 ...
    #>  $ gOldXsi                : num [1:12, 1] -0.704 -1.251 -1.092 -0.231 0.111 ...
    #>  $ gBestXsi               : num [1:12, 1] -0.704 -1.251 -1.092 -0.231 0.111 ...
    #>  $ gTau                   : logi [1, 1] NA
    #>  $ gOldTau                : logi [1, 1] NA
    #>  $ gBestTau               : logi [1, 1] NA
    #>  $ gQuickErrorsXsi        : num [1:12, 1] 0.00513 0.00605 0.00572 0.00479 0.00476 ...
    #>  $ gQuickErrorsTau        : logi [1, 1] NA
    #>  $ gQuickErrorsSigma      : num [1, 1] 0.0015
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gQuickErrorsBeta       : num [1, 1] 0.000866
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gMasterTheta           : num [1:2000, 1] -0.368 -0.215 0.851 0.244 -0.151 ...
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr [1:2000] "" "" "" "" ...
    #>   .. ..$ : chr ""
    #>  $ gTheta                 : num [1:2000, 1] -0.5293 -0.3871 0.6049 0.0401 -0.3274 ...
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr [1:2000] "" "" "" "" ...
    #>   .. ..$ : chr ""
    #>  $ gVariance              : num [1, 1] 0.865
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gOldVariance           : num [1, 1] 0.865
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gBestVariance          : num [1, 1] 0.865
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gHistoWeights          : logi [1, 1] NA
    #>  $ gOldHisto              : logi [1, 1] NA
    #>  $ gBestHisto             : logi [1, 1] NA
    #>  $ gYBeta                 : num [1, 1] 0
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : NULL
    #>   .. ..$ : chr ""
    #>  $ gWtFactor              :List of 4
    #>   ..$ : num 1
    #>   ..$ : num 1
    #>   ..$ : num 1
    #>   ..$ : num 1
    #>  $ gSuffXsi               : num [1:12, 1] -644 -743 -716 -548 -476 -764 -776 -766 -852 -776 ...
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : NULL
    #>   .. ..$ : chr ""
    #>  $ gSuffTau               : logi [1, 1] NA
    #>  $ gModelText             : chr "item"
    #>  $ gFormatText            : chr " pid 1-5 responses 12-23 v1 12 v2 15"
    #>  $ gRegressionText        : chr ""
    #>  $ gGroupText             : chr "v1"
    #>  $ gOSSCP                 : num [1, 1] 0
    #>   ..- attr(*, "dimnames")=List of 2
    #>   .. ..$ : chr ""
    #>   .. ..$ : chr ""
    #>  $ gLOSSCP                : logi [1, 1] NA
    #>  $ gLSSCP                 : logi [1, 1] NA
    #>  $ gFullSSCP              : logi [1, 1] NA
    #>  $ gFullSums              : logi [1, 1] NA
    #>  $ gMinAlpha              : num 0
    #>  $ gModelEstimated        : logi TRUE
    #>  $ gIntegrationMethod     :'data.frame': 7 obs. of  2 variables:
    #>   ..$ gIntegrationMethod    : int [1:7] 1 2 3 4 5 6 7
    #>   ..$ gIntegrationMethodText: chr [1:7] "Bock Aitkin" "Monte Carlo" "Gauss-Hermite Quadrature" "Joint Maximum Likelihood" ...
    #>  $ gPopulation            : int 1
    #>  $ gSeeds                 : int 2
    #>  $ gMaxSinceBests         : int 100
    #>  $ gInnerLoopss           : int 10
    #>  $ gWarningss             : logi TRUE
    #>  $ gEstsToLog             : logi TRUE
    #>  $ gKeepLast              : logi FALSE
    #>  $ gAddExtension          : logi TRUE
    #>  $ gMLEMax                : num 15
    #>  $ gPlotWinMax            : int 100
    #>  $ gZero                  : num 0.3
    #>  $ gRespMiss              : int 2
    #>  $ gDatafileName          : chr "ex1.dat"
    #>  $ gDatafileFormats       : int 0
    #>  $ gDatafileNameDisplay   : chr "ex1.dat"
    #>  $ gStopReason            : int 2
    #>  $ gImplicit              :List of 2
    #>   ..$ Name  :List of 1
    #>   .. ..$ : chr "item"
    #>   ..$ Levels:List of 1
    #>   .. ..$ : int 12
    #>  $ gNImpValue             : int 12
    #>  $ gPIDVar                : int 0
    #>  $ gModelVariables        :List of 2
    #>   ..$ XV: list()
    #>   ..$ IV:List of 1
    #>   .. ..$ : int 0
    #>  $ gNRec                  : int 1
    #>  $ gResponseLookUp        :List of 2
    #>   ..$ VarNumber: int -2
    #>   ..$ Value    :List of 2
    #>   .. ..$ : chr "0"
    #>   .. ..$ : chr "1"
    #>  $ gPreKeyLookUp          :List of 2
    #>   ..$ VarNumber: int -2
    #>   ..$ Value    :List of 6
    #>   .. ..$ : chr "M"
    #>   .. ..$ : chr "a"
    #>   .. ..$ : chr "b"
    #>   .. ..$ : chr "c"
    #>   .. ..$ : chr "d"
    #>   .. ..$ : chr "e"
    #>  $ gNDataRecords          : int 11989
    #>  $ gFacetVariables        :List of 2
    #>   ..$ XV: list()
    #>   ..$ IV: list()
    #>  $ gRegressionVariables   :List of 2
    #>   ..$ XV: list()
    #>   ..$ IV: list()
    #>  $ gGroupVariables        :List of 2
    #>   ..$ XV:List of 1
    #>   .. ..$ : int 1
    #>   ..$ IV: list()
    #>  $ gWeightVariable        :List of 2
    #>   ..$ XV: list()
    #>   ..$ IV: list()
    #>  $ gTDFileV               :List of 2
    #>   ..$ XV: list()
    #>   ..$ IV:List of 1
    #>   .. ..$ : int 0
    #>  $ gValidC                : list()
    #>  $ gFileRebuildNeeded     : logi FALSE
    #>  $ gAMatrixImportFileName : chr ""
    #>  $ gCMatrixImportFileName : chr ""
    #>  $ gHistoryFileName       : chr ""
    #>  $ gTitle                 : chr "ConQuest: Generalised Item Response Modelling Software"
    #>  $ gStoreInRAM            : logi FALSE
    #>  $ gSubmitMode            : logi TRUE
    #>  $ gMaxCats               : int 2
    #>  $ gConvergenceOK         : logi FALSE
    #>  $ gParameterConvCriterion: num 1e-04
    #>  $ gDevianceConvCriterion : num 1e-04
    #>  $ gFitDraws              : int 5
    #>  $ gMaxIterations         : int 1000
    #>  $ gAccuracy              : int 15
    #>  $ gPVNodes               : int 2000
    #>  $ gFitNodes              : int 2000
    #>  $ gIteration             : int 23
    #>   [list output truncated]
    #>  - attr(*, "class")= chr [1:2] "list" "conQuestSysFile"

    # tidy up
    file.remove(
      list.files(myTmpDir, all.files = TRUE, full.names = TRUE, pattern = "^myi|^myS|ex1"),
      recursive=TRUE
    )
    #> [1] TRUE TRUE
    setwd(oldWd)

## Read in a ConQuest system file

The above example created a system file. Alternatively, there is an inbuilt example of a system file.

conquestr can read in a system file, using the `ConQuestSys` function. This function returns a list that includes the response data, parameter estimates, and other data objects created by ‘ACER ConQuest’. These lists can be optionally coerced into R data frames.

    # if no argument is provided to ConQuestSys, the example system file is read in by default.
    myCqs <- ConQuestSys()
    #> no system file provided, loading the example system file instead

You can see the data objects available within the object (e.g., `str(myCqs)`), and some useful objects will be:

- `gResponseData` - The raw response data including information about the raw and key response to each item.
- `gYData` - The regression data included in the estimation.
- `gAllCaseEstimates` - the latent ability estimates (e.g., PVs, WLEs).
- The option `matrixout` is available for several commands and will ensure data objects are saved to the system file - these can be found in `gMatrixList`. For example:
  - The command `matrixsampler` and the option `matrixout` creates the objects `matrixSampler_fit`, `matrixSampler_raw`, `matrix_userfit` (the simulated data) in `gMatrixList`.
  - The command `itanal`, and the option `matrixout` creates the objects `*_counts`, `*_itemstats`, `*_ptbis`, `*_abilitymeansd` (where “*” is a user defined prefix declared in the option `matrixout`) in `gMatrixList` .
  - The command `estimate` and the option `matrixout`… for more information see the manual

Users can search the names of objects in the system file using the helper function `searchConQuestSys`:

    # search for objects named history in myCqs
    searchConQuestSys("history", myCqs)
    #> [1] "gHistoryFileName" "gHistory"         "gCommandHistory"