Move processing of mxData keys
[openmx:openmx.git] / R / MxExpectationRAM.R
1 #
2 #   Copyright 2007-2013 The OpenMx Project
3 #
4 #   Licensed under the Apache License, Version 2.0 (the "License");
5 #   you may not use this file except in compliance with the License.
6 #   You may obtain a copy of the License at
7
8 #        http://www.apache.org/licenses/LICENSE-2.0
9
10 #   Unless required by applicable law or agreed to in writing, software
11 #   distributed under the License is distributed on an "AS IS" BASIS,
12 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #   See the License for the specific language governing permissions and
14 #   limitations under the License.
15
16
17 setClass(Class = "MxExpectationRAM",
18         representation = representation(
19                 A = "MxCharOrNumber",
20                 S = "MxCharOrNumber",
21                 F = "MxCharOrNumber",
22                 M = "MxCharOrNumber",
23                 H = "MxCharOrNumber",
24                 thresholds = "MxCharOrNumber",
25                 dims = "character",
26                 definitionVars = "list",
27                 dataColumns = "numeric",
28                 thresholdColumns = "numeric",
29                 thresholdLevels = "numeric",
30                 depth = "integer",
31                 threshnames = "character",
32                 usePPML = "logical",
33                 ppmlData = "MxData",
34                 OnlyData = "logical"),
35         contains = "MxBaseExpectation")
36
37 setMethod("initialize", "MxExpectationRAM",
38         function(.Object, A, S, F, M, H, dims, thresholds, threshnames, OnlyData,
39                 data = as.integer(NA), name = 'expectation') {
40                 .Object@name <- name
41                 .Object@A <- A
42                 .Object@S <- S
43                 .Object@F <- F
44                 .Object@M <- M
45                 .Object@H <- H
46                 .Object@data <- data
47                 .Object@dims <- dims
48                 .Object@thresholds <- thresholds
49                 .Object@definitionVars <- list()
50                 .Object@threshnames <- threshnames
51                 .Object@usePPML <- FALSE
52                 .Object@OnlyData <- OnlyData
53                 return(.Object)
54         }
55 )
56
57 setMethod("genericExpDependencies", signature("MxExpectationRAM"),
58         function(.Object, dependencies) {
59         sources <- c(.Object@A, .Object@S, .Object@F, .Object@M, .Object@H, .Object@thresholds)
60         sources <- sources[!is.na(sources)]
61         dependencies <- imxAddDependency(sources, .Object@name, dependencies)
62         return(dependencies)
63 })
64
65 setMethod("genericExpFunNamespace", signature("MxExpectationRAM"), 
66         function(.Object, modelname, namespace) {
67                 .Object@name <- imxIdentifier(modelname, .Object@name)
68                 .Object@A <- imxConvertIdentifier(.Object@A, modelname, namespace)
69                 .Object@S <- imxConvertIdentifier(.Object@S, modelname, namespace)
70                 .Object@F <- imxConvertIdentifier(.Object@F, modelname, namespace)
71                 .Object@M <- imxConvertIdentifier(.Object@M, modelname, namespace)
72                 .Object@H <- imxConvertIdentifier(.Object@H, modelname, namespace)
73                 .Object@data <- imxConvertIdentifier(.Object@data, modelname, namespace)
74                 .Object@thresholds <- sapply(.Object@thresholds, 
75                         imxConvertIdentifier, modelname, namespace)
76                 return(.Object)
77 })
78
79 setMethod("genericExpRename", signature("MxExpectationRAM"),
80         function(.Object, oldname, newname) {
81                 .Object@A <- renameReference(.Object@A, oldname, newname)
82                 .Object@S <- renameReference(.Object@S, oldname, newname)
83                 .Object@F <- renameReference(.Object@F, oldname, newname)
84                 .Object@M <- renameReference(.Object@M, oldname, newname)
85                 .Object@H <- renameReference(.Object@H, oldname, newname)
86                 .Object@data <- renameReference(.Object@data, oldname, newname)
87                 .Object@thresholds <- sapply(.Object@thresholds, renameReference, oldname, newname)             
88                 return(.Object)
89 })
90
91 setMethod("genericExpFunConvert", signature("MxExpectationRAM"),
92           function(.Object, flatModel, model, labelsData, defVars, dependencies) {
93                   if (all(is.na(.Object@H))) {
94                           ExpectationRAM.ExpFunConvert(.Object, flatModel, model,
95                                                        labelsData, defVars, dependencies)
96                   } else {
97                           ExpectationRAM.ExpHFunConvert(.Object, flatModel, model,
98                                                         labelsData, defVars, dependencies)
99                   }
100           })
101
102 ExpectationRAM.ExpHFunConvert <- function(.Object, flatModel, model,
103                                           labelsData, defVars, dependencies) {
104         # TODO save a list of the submodels that make up the present hierarchical model
105
106         modelname <- imxReverseIdentifier(model, .Object@name)[[1]]     
107         name <- .Object@name
108         .Object@A <- as.integer(NA)
109         .Object@S <- as.integer(NA)
110         .Object@F <- as.integer(NA)
111         .Object@M <- as.integer(NA)
112         if (is.na(.Object@data)) {
113                 .Object@data <- as.integer(NA)
114         } else {
115                 # remove, only for testing TODO
116                 .Object@data <- as.integer(imxLocateIndex(flatModel, .Object@data, name))
117         }
118         .Object@H <- imxLocateIndex(flatModel, .Object@H, name)
119         .Object@thresholds <- as.integer(NA)
120         .Object@depth <- as.integer(NA)  # need to calc in C TODO
121         return(.Object)
122 }
123
124 ExpectationRAM.ExpFunConvert <- function(.Object, flatModel, model,
125                                          labelsData, defVars, dependencies) {
126         modelname <- imxReverseIdentifier(model, .Object@name)[[1]]     
127         name <- .Object@name
128         aMatrix <- .Object@A
129         sMatrix <- .Object@S
130         fMatrix <- .Object@F
131         mMatrix <- .Object@M
132         data <- .Object@data
133         if(is.na(data)) {
134                 msg <- paste("The RAM expectation function",
135                              "does not have a dataset associated with it in model",
136                              omxQuotes(modelname),
137                              "\nSee ?mxData() to see how to add data to your model")
138                 stop(msg, call. = FALSE)
139         }
140         .Object@data <- as.integer(imxLocateIndex(flatModel, data, name))
141
142         if (.Object@OnlyData) {
143                 .Object@A <- as.integer(NA)
144                 .Object@S <- as.integer(NA)
145                 .Object@F <- as.integer(NA)
146                 .Object@M <- as.integer(NA)
147                 .Object@thresholds <- as.integer(NA)
148                 return(.Object)
149         }
150         
151         mxDataObject <- flatModel@datasets[[data]]
152         if(!is.na(mMatrix) && single.na(mxDataObject@means) && mxDataObject@type != "raw") {
153                 msg <- paste("The RAM expectation function",
154                              "has an expected means vector but",
155                              "no observed means vector in model",
156                              omxQuotes(modelname))
157                 stop(msg, call. = FALSE)
158         }
159         if(!single.na(mxDataObject@means) && is.null(flatModel[[mMatrix]])) {
160                 msg <- paste("The RAM expectation function",
161                              "has an observed means vector but",
162                              "no expected means vector in model",
163                              omxQuotes(modelname))
164                 stop(msg, call. = FALSE)                
165         }
166         checkNumericData(mxDataObject)
167         .Object@A <- imxLocateIndex(flatModel, aMatrix, name)
168         .Object@S <- imxLocateIndex(flatModel, sMatrix, name)
169         .Object@F <- imxLocateIndex(flatModel, fMatrix, name)
170         .Object@M <- imxLocateIndex(flatModel, mMatrix, name)
171         verifyObservedNames(mxDataObject@observed, mxDataObject@means, mxDataObject@type, flatModel, modelname, "RAM")
172         fMatrix <- flatModel[[fMatrix]]@values
173         if (is.null(dimnames(fMatrix))) {
174                 msg <- paste("The F matrix of model",
175                              omxQuotes(modelname), "does not contain dimnames")
176                 stop(msg, call. = FALSE)
177         }
178         if (is.null(dimnames(fMatrix)[[2]])) {
179                 msg <- paste("The F matrix of model",
180                              omxQuotes(modelname), "does not contain colnames")
181                 stop(msg, call. = FALSE)
182         }
183         mMatrix <- flatModel[[mMatrix]]         
184         if(!is.null(mMatrix)) {
185                 means <- dimnames(mMatrix)
186                 if (is.null(means)) {
187                         msg <- paste("The M matrix associated",
188                                      "with the RAM expectation function in model", 
189                                      omxQuotes(modelname), "does not contain dimnames.")
190                         stop(msg, call. = FALSE)        
191                 }
192                 meanRows <- means[[1]]
193                 meanCols <- means[[2]]
194                 if (!is.null(meanRows) && length(meanRows) > 1) {
195                         msg <- paste("The M matrix associated",
196                                      "with the RAM expectation function in model", 
197                                      omxQuotes(modelname), "is not a 1 x N matrix.")
198                         stop(msg, call. = FALSE)
199                 }
200                 if (!identical(dimnames(fMatrix)[[2]], meanCols)) {
201                         msg <- paste("The column names of the F matrix",
202                                      "and the column names of the M matrix",
203                                      "in model", 
204                                      omxQuotes(modelname), "do not contain identical",
205                                      "names.")
206                         stop(msg, call. = FALSE)
207                 }
208         }
209         translatedNames <- fMatrixTranslateNames(fMatrix, modelname)
210         .Object@depth <- generateRAMDepth(flatModel, aMatrix, model@options)
211         if (mxDataObject@type == 'raw') {
212                 threshName <- .Object@thresholds
213                 checkNumberOrdinalColumns(mxDataObject)
214                 .Object@definitionVars <- imxFilterDefinitionVariables(defVars, data)
215                 .Object@dataColumns <- generateDataColumns(flatModel, translatedNames, data)
216                 verifyThresholds(flatModel, model, labelsData, data, translatedNames, threshName)
217                 .Object@thresholds <- imxLocateIndex(flatModel, threshName, name)
218                 retval <- generateThresholdColumns(flatModel, model, labelsData, translatedNames, data, threshName)
219                 .Object@thresholdColumns <- retval[[1]]
220                 .Object@thresholdLevels <- retval[[2]]
221                 if (length(mxDataObject@observed) == 0) {
222                         .Object@data <- as.integer(NA)
223                 }
224                 if (single.na(.Object@dims)) {
225                         .Object@dims <- translatedNames
226                 }
227         } else {
228                 .Object@thresholds <- as.integer(NA)
229                 targetNames <- rownames(mxDataObject@observed)
230                 if (!identical(translatedNames, targetNames)) {
231                         varsNotInData <- translatedNames[!(translatedNames %in% targetNames)]
232                         msg <- paste("The names of the manifest",
233                                      "variables in the F matrix of model",
234                                      omxQuotes(modelname), "does not match the",
235                                      "dimnames of the observed covariance matrix.")
236                         if (length(varsNotInData) > 0) {
237                                 msg <- paste(msg,
238                                              "To get you started, the following variables are used but",
239                                              "are not in the observed data:", 
240                                              omxQuotes(varsNotInData))
241                         }
242                         stop(msg, call. = FALSE)
243                 }
244         }
245         return(.Object)
246 }
247
248 generateRAMDepth <- function(flatModel, aMatrixName, modeloptions) {
249         mxObject <- flatModel[[aMatrixName]]
250         if (!is(mxObject, "MxMatrix")) {
251                 return(as.integer(NA))
252         }
253         if (identical(modeloptions[['RAM Inverse Optimization']], "No")) {
254                 return(as.integer(NA))
255         }
256         if (is.null(modeloptions[['RAM Inverse Optimization']]) &&
257                 identical(getOption('mxOptions')[['RAM Inverse Optimization']], "No")) {
258                 return(as.integer(NA))
259         }       
260         maxdepth <- modeloptions[['RAM Max Depth']]
261         if (is.null(maxdepth) || (length(maxdepth) != 1) ||
262                 is.na(maxdepth) || !is.numeric(maxdepth) || maxdepth < 0) {
263                 maxdepth <- nrow(mxObject) - 1
264         }
265         return(omxGetRAMDepth(mxObject, maxdepth))
266 }
267
268 omxGetRAMDepth <- function(A, maxdepth = nrow(A) - 1) {
269         mxObject <- A
270         aValues <- matrix(0, nrow(mxObject), ncol(mxObject))
271         defvars <- apply(mxObject@labels, c(1,2), imxIsDefinitionVariable)
272         squarebrackets <- mxObject@.squareBrackets
273         aValues[mxObject@free] <- 1
274         aValues[mxObject@values != 0] <- 1
275         aValues[defvars] <- 1
276         aValues[squarebrackets] <- 1
277         return(generateDepthHelper(aValues, aValues, 0, maxdepth))
278 }
279
280 generateDepthHelper <- function(aValues, currentProduct, depth, maxdepth) {
281         if (depth > maxdepth) {
282                 return(as.integer(NA))
283         }
284         if (all(currentProduct == 0)) { 
285                 return(as.integer(depth))
286         } else {
287                 return(generateDepthHelper(aValues, currentProduct %*% aValues, depth + 1, maxdepth))
288         }
289 }
290
291 fMatrixTranslateNames <- function(fMatrix, modelName) {
292         retval <- character()
293         colNames <- dimnames(fMatrix)[[2]]
294         for(i in 1:nrow(fMatrix)) {
295                 irow <- fMatrix[i,]
296                 matches <- which(irow == 1)
297                 if (length(matches) != 1) {
298                         err <- paste("The model",
299                                 omxQuotes(modelName), "does not contain",
300                                 "a valid F matrix")
301                         stop(err, call. = FALSE)
302                 }
303                 retval[[i]] <- colNames[[matches[[1]]]]
304         }
305         return(retval)
306 }
307
308 updateRAMdimnames <- function(flatExpectation, flatJob) {
309         fMatrixName <- flatExpectation@F
310         mMatrixName <- flatExpectation@M
311         if (is.na(mMatrixName)) {
312                 mMatrix <- NA
313         } else {
314                 mMatrix <- flatJob[[mMatrixName]]
315         }
316         fMatrix <- flatJob[[fMatrixName]]
317         if (is.null(fMatrix)) {
318                 modelname <- getModelName(flatExpectation)
319                 stop(paste("Unknown F matrix name", 
320                         omxQuotes(simplifyName(fMatrixName, modelname)),
321                         "detected in the RAM expectation function",
322                         "of model", omxQuotes(modelname)), call. = FALSE)
323         }
324         dims <- flatExpectation@dims
325         if (!is.null(dimnames(fMatrix)) && !single.na(dims) && 
326                 !identical(dimnames(fMatrix)[[2]], dims)) {
327                 modelname <- getModelName(flatExpectation)
328                 msg <- paste("The F matrix associated",
329                         "with the RAM expectation function in model", 
330                         omxQuotes(modelname), "contains dimnames and",
331                         "the expectation function has specified dimnames")
332                 stop(msg, call.=FALSE)          
333         }
334         if (is.null(dimnames(fMatrix)) && !single.na(dims)) {
335                 dimnames(flatJob[[fMatrixName]]) <- list(c(), dims)
336         }
337
338         if (!isS4(mMatrix) && (is.null(mMatrix) || is.na(mMatrix))) {
339                 return(flatJob)
340         }
341
342         if (!is.null(dimnames(mMatrix)) && !single.na(dims) &&
343                 !identical(dimnames(mMatrix), list(NULL, dims))) {
344                 modelname <- getModelName(flatExpectation)
345                 msg <- paste("The M matrix associated",
346                         "with the RAM expectation function in model", 
347                         omxQuotes(modelname), "contains dimnames and",
348                         "the expectation function has specified dimnames")
349                 stop(msg, call.=FALSE)  
350         }
351
352         if (is.null(dimnames(mMatrix)) && !single.na(dims)) {
353                 dimnames(flatJob[[mMatrixName]]) <- list(NULL, dims)
354         }
355
356         return(flatJob)
357 }
358
359 setMethod("genericExpAddEntities", "MxExpectationRAM",
360           function(.Object, job, flatJob, labelsData) {
361                   precision <- "Function precision"
362                   if(!single.na(.Object@thresholds)) {
363                           if (is.null(job@options[[precision]])) {
364                                   job <- mxOption(job, precision, 1e-9)
365                           }
366                   }
367
368                   ppmlModelOption <- job@options$UsePPML
369                   if (is.null(ppmlModelOption)) {
370                           enablePPML <- (getOption("mxOptions")$UsePPML == "Yes")
371                   } else {
372                           enablePPML <- (ppmlModelOption == "Yes")
373                   }
374
375                   if (enablePPML) {
376                           aMatrix <- job[[.Object@A]]
377                           aMatrixFixed <- !is.null(aMatrix) && is(aMatrix, "MxMatrix") && all(!aMatrix@free)
378                           enablePPML <- aMatrixFixed
379                   }
380
381                   if (enablePPML) {
382                           job <- imxPPMLTransformModel(job)
383                           job@.newobjects <- TRUE
384                   }
385
386                   return(job)
387           })
388
389 setMethod("genericExpConvertEntities", "MxExpectationRAM",
390         function(.Object, flatModel, namespace, labelsData) {
391                 if (all(is.na(.Object@H))) {
392                         flatModel <- ExpectationRAM.ConvertEntities(.Object, flatModel, namespace, labelsData)
393                 } else {
394                         flatModel <- ExpectationRAM.ConvertEntitiesH(.Object, flatModel, namespace, labelsData)
395                 }
396
397                 return(flatModel)
398         }
399 )
400
401 ExpectationRAM.ConvertEntitiesH <- function(.Object, flatModel, namespace, labelsData) {
402                                         # verify dimensions of H matrices TODO
403         ## cache <- new.env(parent = emptyenv())
404         ## hmatrix <- list()
405         ## for (hx in 1:length(.Object@H)) {
406         ##      tuple <- evaluateMxObject(.Object@H[hx], flatModel, labelsData, cache)
407         ##      hmatrix[[hx]] <- tuple[[1]]
408         ## }
409
410                                         # complain appropriately if match fails TODO
411         exp.filter <- sapply(flatModel@expectations,
412                               function (exp) length(exp@container) && exp@container == .Object@name)
413         datasets <- sapply(flatModel@expectations[exp.filter],
414                            function (exp) exp@data)
415         data.filter <- match(datasets, names(flatModel@datasets))
416
417         for (dx in data.filter) {
418                 data <- flatModel@datasets[[dx]]
419                 if (data@type != "raw") {
420                         stop(paste("Hierarchical level", data@name,
421                                    "must have raw data, not", data@type))
422                 }
423         }
424         return(flatModel)
425 }
426
427 ExpectationRAM.ConvertEntities <- function(.Object, flatModel, namespace, labelsData) {
428         cache <- new.env(parent = emptyenv())
429
430         if(is.na(.Object@data)) {
431                 modelname <- getModelName(.Object)
432                 msg <- paste("The RAM expectation function",
433                              "does not have a dataset associated with it in model",
434                              omxQuotes(modelname))
435                 stop(msg, call.=FALSE)
436         }
437
438         # allow a linking table passed as a RAM model
439         if (.Object@OnlyData) return(flatModel)
440
441         tuple <- evaluateMxObject(.Object@A, flatModel, labelsData, cache)
442         Amatrix <- tuple[[1]]
443         cache <- tuple[[2]]
444         tuple <- evaluateMxObject(.Object@S, flatModel, labelsData, cache)
445         Smatrix <- tuple[[1]]
446         cache <- tuple[[2]]
447         if (!identical(dim(Amatrix), dim(Smatrix))) {
448                 modelname <- getModelName(.Object)
449                 msg <- paste("The RAM expectation function",
450                              "in model", omxQuotes(modelname), "has an A matrix",
451                              "with dimensions", nrow(Amatrix), 'x', ncol(Amatrix),
452                              "and a S matrix with dimensions", nrow(Smatrix), 'x',
453                              ncol(Smatrix))
454                 stop(msg, call.=FALSE)
455         }
456
457         flatModel <- updateRAMdimnames(.Object, flatModel)
458
459         if (flatModel@datasets[[.Object@data]]@type != 'raw') {
460                 return(flatModel)
461         }
462
463         if (is.na(.Object@M) || is.null(flatModel[[.Object@M]])) {
464                 modelname <- getModelName(.Object)
465                 msg <- paste("The RAM expectation function",
466                              "has raw data but is missing",
467                              "an expected means vector in model",
468                              omxQuotes(modelname))
469                 stop(msg, call.=FALSE)
470         }
471         
472         flatModel <- updateThresholdDimnames(.Object, flatModel, labelsData)
473 }
474
475 imxSimpleRAMPredicate <- function(model) {
476         if (is.null(model$expectation) || !is(model$expectation, "MxExpectationRAM")) {
477                 return(FALSE)
478         }
479         nameA <- model$expectation@A
480         nameS <- model$expectation@S
481         A <- model[[nameA]]
482         S <- model[[nameS]]
483         if (is.null(A) || is.null(S)) {
484                 return(FALSE)
485         }
486         return(is(A, "MxMatrix") && is(S, "MxMatrix"))
487 }
488
489 mxExpectationRAM <- function(A="A", S="S", F="F", M = NA, dimnames = NA, thresholds = NA,
490         threshnames = dimnames, H=character(0), OnlyData=FALSE) {
491
492         if (typeof(A) != "character") {
493                 msg <- paste("argument 'A' is not a string",
494                         "(the name of the 'A' matrix)")
495                 stop(msg)
496         }       
497         if (typeof(S) != "character") {
498                 msg <- paste("argument 'S' is not a string",
499                         "(the name of the 'S' matrix)")
500                 stop(msg)
501         }
502         if (typeof(F) != "character") {
503                 msg <- paste("argument 'F' is not a string",
504                         "(the name of the 'F' matrix)")
505                 stop(msg)
506         }
507         if (!(single.na(M) || typeof(M) == "character")) {
508                 msg <- paste("argument M is not a string",
509                         "(the name of the 'M' matrix)")
510                 stop(msg)
511         }
512         if (missing(H)) {
513                 # ok
514         } else {
515                 if (!missing(A) || !missing(S) || !missing(F) || !missing(M)) {
516                         stop(paste("A, S, F, and M matrices cannot be",
517                                    "specified in the hierarchical container model"))
518                 }
519                 if (!missing(dimnames) || !missing(thresholds) || !missing(threshnames)) {
520                         stop(paste("dimnames, thresholds, and threshnames cannot be",
521                                    "specified in the hierarchical container model"))
522                 }
523                 A <- as.integer(NA)
524                 S <- as.integer(NA)
525                 F <- as.integer(NA)
526         }
527         if (is.na(M)) M <- as.integer(NA)
528         if (single.na(thresholds)) thresholds <- as.character(NA)
529         if (single.na(dimnames)) dimnames <- as.character(NA)
530         if (single.na(threshnames)) threshnames <- as.character(NA)
531         if (!is.vector(dimnames) || typeof(dimnames) != 'character') {
532                 stop("Dimnames argument is not a character vector")
533         }
534         if (!is.vector(threshnames) || typeof(threshnames) != 'character') {
535                 stop("'threshnames' argument is not a character vector")
536         }
537         if (length(thresholds) != 1) {
538                 stop("Thresholds argument must be a single matrix or algebra name")
539         }
540         if (length(dimnames) == 0) {
541                 stop("Dimnames argument cannot be an empty vector")
542         }
543         if (length(threshnames) == 0) {
544                 stop("'threshnames' argument cannot be an empty vector")
545         }
546         if (length(dimnames) > 1 && any(is.na(dimnames))) {
547                 stop("NA values are not allowed for dimnames vector")
548         }
549         if (length(threshnames) > 1 && any(is.na(threshnames))) {
550                 stop("NA values are not allowed for 'threshnames' vector")
551         }
552         return(new("MxExpectationRAM", A, S, F, M, H, dimnames, thresholds, threshnames, OnlyData))
553 }
554
555 displayMxExpectationRAM <- function(expectation) {
556         cat("MxExpectationRAM", omxQuotes(expectation@name), '\n')
557         if (length(expectation@container)) {
558                 cat("@container :", omxQuotes(expectation@container), '\n')
559         }
560         if (length(expectation@submodels)) {
561                 cat("@submodels :", omxQuotes(expectation@submodels), '\n')
562         }
563         if (all(is.na(expectation@H))) {
564                 cat("@A :", omxQuotes(expectation@A), '\n')
565                 cat("@S :", omxQuotes(expectation@S), '\n')
566                 cat("@F :", omxQuotes(expectation@F), '\n')
567         } else {
568                 cat("@H :", omxQuotes(expectation@H), '\n')
569         }
570         if (is.na(expectation@M)) {
571                 cat("@M :", expectation@M, '\n')
572         } else {
573                 cat("@M :", omxQuotes(expectation@M), '\n')
574         }
575         if (single.na(expectation@dims)) {
576                 cat("@dims : NA \n")
577         } else {
578                 cat("@dims :", omxQuotes(expectation@dims), '\n')
579         }               
580         if (single.na(expectation@thresholds)) {
581                 cat("@thresholds : NA \n")
582         } else {
583                 cat("@thresholds :", omxQuotes(expectation@thresholds), '\n')
584         }
585         invisible(expectation)
586 }
587
588 setMethod("print", "MxExpectationRAM", function(x,...) { 
589         displayMxExpectationRAM(x) 
590 })
591
592 setMethod("show", "MxExpectationRAM", function(object) { 
593         displayMxExpectationRAM(object) 
594 })