#options(error = browser) #options(warn = 2) library(testthat) library(OpenMx) library(rpf) suppressWarnings(RNGversion("3.5")) set.seed(9) dir <- tempdir() # safe place to create files numItems <- 10 i1 <- rpf.drm(multidimensional=TRUE) items <- vector("list", numItems) correct <- vector("list", numItems) for (ix in 1:numItems) { items[[ix]] <- i1 correct[[ix]] <- rpf.rparam(i1, version=1) correct[[ix]][3] <- logit(0) correct[[ix]][4] <- logit(1) } correct.mat <- simplify2array(correct) correct.mat[2,] <- correct.mat[2,] * -correct.mat[1,] ability <- rnorm(500) data <- rpf.sample(ability, items, correct.mat) if (0) { write.table(sapply(data, unclass)-1, file="drm1.csv", quote=FALSE, row.names=FALSE, col.names=FALSE) } cols <- colnames(data) data <- data[,sample.int(numItems)] ip.mat <- mxMatrix(name="item", nrow=4, ncol=numItems, values=c(1,0, logit(0), logit(1)), free=c(TRUE, TRUE, FALSE, FALSE)) rownames(ip.mat) <- c('f1','b','g','u') colnames(ip.mat) <- cols m1 <- mxModel(model="drm1", ip.mat, mxData(observed=data, type="raw"), mxExpectationBA81(items, qpoints=31, debugInternal=TRUE), mxFitFunctionML(), mxComputeSequence(list( mxComputeOnce('expectation', 'scores'), mxComputeReportExpectation() ))) m2 <- mxRun(m1) omxCheckCloseEnough(fivenum(m2$expectation$debug$patternLikelihood), c(-7.5454472, -7.3950031, -7.3950031, -6.9391761, -3.5411989), .001) omxCheckCloseEnough(sum(m2$expectation$debug$em.expected), 5000, .01) omxCheckCloseEnough(fivenum(m2$expectation$debug$em.expected), c(0, 5.86e-05, 0.0687802, 7.1582354, 74.1583248), .01) em.ex <- array(c(m2$expectation$debug$em.expected), dim=c(2,31,20)) em.tbl <- rbind(apply(em.ex[1,,], 2, sum)[1:numItems], apply(em.ex[2,,], 2, sum)[1:numItems]) omxCheckCloseEnough(apply(sapply(data[,cols], unclass)-1, 2, table), em.tbl, .01) testDeriv <- mxModel(m2, mxComputeSequence(list( mxComputeOnce('expectation', 'scores'), mxComputeOnce('fitfunction', c('fit', 'gradient', 'hessian', 'ihessian')), mxComputeReportDeriv() ))) testDeriv <- mxRun(testDeriv) omxCheckCloseEnough(testDeriv$fitfunction$result, 2*3221.826, .01) omxCheckCloseEnough(fivenum(testDeriv$output$gradient), 2*c(-128.034, -8.294, 10.7, 25.814, 107.966), .01) omxCheckCloseEnough(fivenum(testDeriv$output$hessian[testDeriv$output$hessian != 0]), 2*c(6.559, 6.559, 32.976, 83.554, 107.714), .01) omxCheckCloseEnough(solve(testDeriv$output$hessian), testDeriv$output$ihessian, 1e-2) m2 <- mxModel(m2, mxExpectationBA81(ItemSpec=items, qpoints=31), mxComputeSequence(list( mxComputeEM(estep=mxComputeOnce('expectation', 'scores'), mstep=mxComputeSequence(list( mxComputeNewtonRaphson(), mxComputeCheckpoint(path=file.path(dir,"em.csv")), mxComputeOnce('expectation')))), mxComputeOnce('fitfunction', 'gradient'), mxComputeReportDeriv()))) # m2 <- mxOption(m2, "Analytic Gradients", 'Yes') # m2 <- mxOption(m2, "Verify level", '-1') # m2 <- mxOption(m2, "Function precision", '1.0E-5') m2 <- mxRun(m2) omxCheckCloseEnough(max(abs(m2$output$gradient)), 0, .033) omxCheckEquals(m2$output$status$code, 0) emstat <- m2$compute$steps[[1]]$output omxCheckCloseEnough(emstat$EMcycles, 10, 1) omxCheckCloseEnough(emstat$totalMstep, 33, 5) omxCheckCloseEnough(m2$output$evaluations, 59, 5) #print(m2$matrices$item$values) #print(correct.mat) omxCheckEquals(m2$output$fitUnits, "-2lnL") omxCheckCloseEnough(m2$fitfunction$result, 6216.272, .01) omxCheckCloseEnough(summary(m2)$informationCriteria['AIC:','par'], 6256.27, .02) omxCheckCloseEnough(summary(m2)$informationCriteria['BIC:','par'], 6340.56, .02) omxCheckTrue(all(m2$item$lbound['f1',] == 1e-6)) omxCheckTrue(all(is.na(m2$item$lbound[2:nrow(m2$item),]))) omxCheckTrue(all(is.na(m2$item$ubound))) emlog <- read.table(file.path(dir,"em.csv"), header=TRUE, sep="\t", stringsAsFactors=FALSE, check.names=FALSE) expect_equal(nrow(emlog), emstat$EMcycles) short <- mxModel(m1, mxComputeEM(estep=mxComputeOnce('expectation', 'scores'), mstep=mxComputeSequence(list( mxComputeNewtonRaphson(), mxComputeOnce('expectation'))), maxIter=4)) short <- mxRun(short, suppressWarnings = TRUE) omxCheckEquals(short$output$status$code, 4) refModels <- mxRefModels(m2, run=TRUE) ind <- refModels[['Independence']] omxCheckCloseEnough(ind$output$fit, 6382.24, .01) omxCheckCloseEnough(summary(ind)$informationCriteria['AIC:','par'], 6402.24, .02) omxCheckCloseEnough(summary(ind)$informationCriteria['BIC:','par'], 6444.39, .02) got <- cor(c(m2$matrices$item$values[1:2,]), c(correct.mat[1:2,])) omxCheckCloseEnough(got, .988, .01) grp <- as.IFAgroup(m2) if (0) { mf <- multinomialFit(grp) omxCheckCloseEnough(mf$df, 269, .1) omxCheckCloseEnough(mf$statistic, 750.6623, .1) mf <- multinomialFit(as.IFAgroup(ind)) omxCheckCloseEnough(mf$df, 279, .1) omxCheckCloseEnough(mf$statistic, 916.63, .1) } scores <- EAPscores(grp) omxCheckIdentical(colnames(scores)[1], "f1") omxCheckCloseEnough(scores[1:5,1], c(0.6783773, 0.2848123, -0.3438632, -0.1026575, -1.0820213), .001) omxCheckCloseEnough(scores[1:5,2], c(0.6769653, 0.6667262, 0.6629124, 0.6624804, 0.6796952), 1e-4) omxCheckCloseEnough(scores[,1], as.vector(ability), 3.5*max(scores[,2])) omxCheckCloseEnough(cor(c(scores[,1]), ability), .737, .01) m3 <- mxModel(m2, mxFitFunctionML(vector=TRUE), mxComputeOnce('fitfunction', 'fit')) m3 <- expect_warning(mxRun(m3, silent=TRUE), "Fixing model by adding mxAlgebra") omxCheckCloseEnough(-2 * sum(log(m3$fitfunction$result)), 6216.272, .01) #mxOption(NULL, 'loglikelihoodScale', -2) i1 <- mxModel(m2, mxComputeSequence(steps=list( mxComputeOnce('expectation', 'scores'), mxComputeOnce('fitfunction', 'information', "hessian"), mxComputeStandardError(), mxComputeHessianQuality()))) i1 <- mxRun(i1, silent=TRUE) #cat(deparse(round(i1$output$standardErrors,3))) se <- c(0.11, 0.102, 0.141, 0.131, 0.109, 0.097, 0.118, 0.099, 0.095, 0.092, 0.124, 0.112, 0.105, 0.095, 0.118, 0.108, 0.102, 0.094, 0.111, 0.11) omxCheckCloseEnough(c(i1$output$standardErrors), se, .01) i1 <- mxModel(m2, mxComputeSequence(steps=list( mxComputeOnce('fitfunction', 'information', "meat"), mxComputeStandardError(), mxComputeHessianQuality()))) i1 <- mxRun(i1, silent=TRUE) se <- c(0.166, 0.111, 0.253, 0.17, 0.171, 0.104, 0.199, 0.11, 0.138, 0.095, 0.195, 0.128, 0.158, 0.102, 0.192, 0.123, 0.149, 0.099, 0.153, 0.114) omxCheckCloseEnough(c(i1$output$standardErrors), se, .001) i2 <- mxModel(m2, mxComputeSequence(steps=list( mxComputeOnce('fitfunction', 'information', "sandwich"), mxComputeStandardError(), mxComputeHessianQuality()))) i2 <- mxRun(i2, silent=TRUE) omxCheckCloseEnough(log(i2$output$conditionNumber), 2, .1) #cat(deparse(round(i2$output$standardErrors,3))) swse <- c(0.161, 0.109, 0.238, 0.161, 0.166, 0.104, 0.194, 0.109, 0.131, 0.094, 0.213, 0.13, 0.167, 0.101, 0.188, 0.12, 0.157, 0.098, 0.157, 0.113) omxCheckCloseEnough(c(i2$output$standardErrors), swse, .001) i3 <- mxBootstrap(m2, 50) bq1 <- summary(i3)[['bootstrapQuantile']] omxCheckCloseEnough(cor(bq1[,2] - bq1[,1], i2$output$standardErrors), 1.0, 0.2) cdata <- compressDataFrame(data) cdata$freq <- as.numeric(cdata$freq) i4 <- mxBootstrap(mxModel(m2, mxData(observed=cdata, type="raw", weight = "freq")), 50) bq2 <- summary(i4)[['bootstrapQuantile']] omxCheckCloseEnough(cor(apply(bq2, 1, diff), i2$output$standardErrors), 1.0, 0.15)