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.

Log in or register to post comments