You are here

Using MxModel names (that include spaces) in MxAlgebras

13 posts / 0 new
Last post
Ryne's picture
Offline
Joined: 07/31/2009 - 15:12
Using MxModel names (that include spaces) in MxAlgebras

I'm writing a helper function that takes a set of existing MxModels and returns a parent model that (a) includes them all as submodels, and (b) has an mxAlgebraObjective that sums the objectives of the existing MxModels. I have always avoided putting spaces in MxModel names when I plan to use that model in an algebra. Is it possible to refer to the objective slot in a model named "My Poorly Named Model" in an MxAlgebra? All of my usual tricks involving quotes don't work.

ryne

tbates's picture
Offline
Joined: 07/31/2009 - 14:25
Maybe rename the models

Maybe rename the models first, replacing illegal characters?

It's a pain when people want to enter your name into a calculator – can't call your kids µ or anything cute :-)

Ryne's picture
Offline
Joined: 07/31/2009 - 15:12
I thought about that.

I thought about that. Renaming would work, because you couldn't refer to the space-name model elsewhere in the model tree without hitting the same error. It's possible that someone could pass "model1" and "model 1" as different models, and that I'd create a conflict by renaming. I'm still not thrilled about changing people's models behind their backs, and if "Model 1" is a valid model name, then we should have a way to get full functionality in algebras. I was leaning towards an error unless someone has a way to include a variation of "Model 1".objective in an algebra, though screening for spaces may take more lines than the rest of the function.

Relevant to Tim's joke: http://xkcd.com/327/

tbates's picture
Offline
Joined: 07/31/2009 - 14:25
Probably ok to replace " "

Probably ok to replace " " with "_" to avoid the model 1 = model1 problem.

ti;rm -r *;bates

tbrick's picture
Offline
Joined: 07/31/2009 - 15:10
Standard R practice tends to

Standard R practice tends to replace spaces with a '.'; some places prefer '_'. As long as you catch the case where two models are identical and either handle it or throw an appropriate error, it should be fine.

I think the code to sub out spaces is something like newString <- gsub("[ ]", ".", oldString).

mspiegel's picture
Offline
Joined: 07/31/2009 - 15:24
There is a solution to this

There is a solution to this problem. I'll look it up in the OpenMx code base and post this evening.

Ryne's picture
Offline
Joined: 07/31/2009 - 15:12
I did figure out the gsub to

I did figure out the gsub to replace non-alphanumerics with a "_". I'd like to avoid the dot, just because someone could name a model "Whatever data" or "whatever objective" and then we'd have real problems. Mike, if you have a solution that keeps me from renaming people's models, let me know!

newNames <- gsub('[^[:alnum:]_]', "_", modelNames)
if (sum(newNames==modelNames)!=numModels)message("Model names used in algebras should avoid spaces and punctuation that can be confused for algebraic terms. Non-alphanumeric characters replaced with '_'.")
mspiegel's picture
Offline
Joined: 07/31/2009 - 15:24
There's probably a fancier

There's probably a fancier way to do it, but the following will work. I'm assuming that 'modelnames' is a vector of strings.

addDotObjective <- function(modelname) {
  return(paste(modelname, "objective", sep = "."))
}

makeAlgebraSummation <- function(modelnames) {
  modelnames <- lapply(modelnames, addDotObjective)
  modelnames <- lapply(modelnames, as.symbol)
  if (length(modelnames) == 1) {
    return(eval(substitute(mxAlgebra(`x`, name = 'sum'), 
      list(x = modelnames[[1]]))))
  } else if (length(modelnames) == 2) {
    return(eval(substitute(mxAlgebra(`x` + `y`, name = 'sum'), 
      list(x = modelnames[[1]], y = modelnames[[2]]))))
  } else {
    expression <- substitute(`x` + `y`, 
      list(x = modelnames[[1]], y = modelnames[[2]]))
    for(i in 3:length(modelnames)) {
      expression <- substitute(x + `y`,
      list(x = expression, y = modelnames[[i]]))
    }
    return(eval(substitute(mxAlgebra(x, name = 'sum'),
      list(x = expression))))
  }
}
Ryne's picture
Offline
Joined: 07/31/2009 - 15:12
I thought you were figuring

I thought you were figuring out a way to include spaces in model names. Sorry to make you do extra work, but I had a solution once the model names are scrubbed. I'll post complete code when the library this goes in is done.

Here's what I came up with for pasting it all together into an algebra. I used the gsub above to swap out non-alphanumerics for "_", but I'd like to better preserve people's model names if possible. newNames is assumed to be a vector of model names (after I scrub out the spaces and junk). alg is then the new mxAlgebra. Industrious users can probably figure out the rest of the function from there.

exp <- paste(newNames, ".objective", sep="")
exp <- paste(exp, collapse=" + ")
algName <- paste("name=", objName, "", sep="\"")
alg <- paste("mxAlgebra(", exp, ",", algName, ")")
alg <- eval(parse(text=alg))
mspiegel's picture
Offline
Joined: 07/31/2009 - 15:24
The following doesn't

The following doesn't work?

exp <- paste(newNames, ".objective", sep="")
exp <- sapply(exp, function(x) { paste("`", x, "`", sep = "") })
exp <- paste(exp, collapse=" + ")
algName <- paste("name=", objName, "", sep="\"")
alg <- paste("mxAlgebra(", exp, ",", algName, ")")
alg <- eval(parse(text=alg))
Ryne's picture
Offline
Joined: 07/31/2009 - 15:12
No. mxAlgebra breaks if I try

No. mxAlgebra breaks if I try any variation on 'Model 1'.objective, and the algebraObjective breaks if I try 'Model 1.objective'. If I use single quotes, I get an algebra objective error "non-numeric argument to binary operator. With the apostrophe/accent/thingee-under-the-tilde, the error is "object 'Model 1.objective' not found." Mixing the quoting and dot references seems to be what's throwing it off.

Edit: added some testing code if anyone wants it.

modelA <- mxModel("Model 1",
    mxData(matrix(1, dimnames=list("x", "x")), "cov", numObs=100),
    mxMatrix("Symm", 1, 1, TRUE, 0, "a", name="S"),
    mxMLObjective("S", dimnames="x")
    )
modelB <- mxModel("Model 2",
    mxData(matrix(2, dimnames=list("x", "x")), "cov", numObs=100),
    mxMatrix("Symm", 1, 1, TRUE, 0, "a", name="S"),
    mxMLObjective("S", dimnames="x")
    )
mult <- mxModel("Mult",
    modelA, modelB,
    mxAlgebra(`Model A.objective` + `Model B.objective`, name="C"),
    mxAlgebraObjective("C")
    ) 
test <- mxRun(mult)
mspiegel's picture
Offline
Joined: 07/31/2009 - 15:24
Umm, shouldn't that be

Umm, shouldn't that be mxAlgebra(Model 1.objective + Model 2.objective, name="C").

Ryne's picture
Offline
Joined: 07/31/2009 - 15:12
Wow. I forgot how to count to

Wow. I forgot how to count to B. I spent half the day trying variations on model 1.objective, then did the rest of my testing with letters and numbers mixed up. Thanks, Mike.