help for ?mxModel notes that if you provide a model as the first parameter of mxModel(), then "all elements of that model are placed in the resulting MxModel object"
Given that, I assume that given an input "share" which has type=RAM
Yes, it is redundant to re-specify the type. When the first argument to mxModel is a model, then a copy of that model is used as the starting point for the model that will be returned from the function (pass by value). Also, if a path is specified with the same "from" and "to" fields as a path that already exists, it will overwrite the existing path.
type="x" is there so that other path-able model formulations can be used. For instance, Paras is looking at implementing type="LISREL". Until there is a second model type, type= is redundant. Don't rely on it remaining so.
I think the context here was not not "redundant as in doesn't get used" but rather "redundant" in that it will be imported from the model passed in as parameter 1, so setting it again is ... overkill"
Is that correct? I think already you can't leave out type="RAM", and expect to set paths... I bumped into this with a supermodel (container) that had no type set, and when I tried to drop paths it said "model type does not take paths"
I see. You are correct. It doesn't hurt to set type="RAM" twice, but is unnecessary. However, we do insist that you set type="RAM" if you plan to use mxPath. One might consider using mxPath as implying type="RAM", and while that could work for the moment, it will break in the long run, so we have insisted on people being explicit about type="RAM" now so that their code won't break when type="LISREL" is implemented.
when you make a model containing models, I see that the new container does not know about the latentVars and manifestVars of its nestlings.
Questions:
Can nestlings have different latentVars and manifestVars from each other?
What is the purpose of latentVars and manifestVars for containers?
2a: If it is too allow communication with the nestlings, then I think the super-model's latentVars and manifestVars should automatically updated to be the intersection of the nested models latentVars and manifestVars?
That way you can't get things out of whack.
Just for context, this arose for me in changing from this
Build DZ group based on MZ just change the data and A-coefficient
DZ = mxModel(MZ, name="DZ",
mxPath(from="A1", to="A2", arrows=2, free=FALSE, values=.5), # overwrite: value = .5 for DZ
mxData(dzfData, type="raw")
)
Make a super-model to contain both the MZ and DZ groups
twinACEModel <- mxModel("twinACE", type="RAM", # have to call this RAM, so it will accept paths later on
# oops, also need to add latent and manifest here, but have not yet
MZ, DZ,
mxAlgebra(MZ.objective + DZ.objective, name="twin"),
mxAlgebraObjective("twin") # the algebra we are trying to minimise
)
I wrote a modified script for univariate ACE to AE... but the fit didn't change when dropping C.
The relevant code-chunk is this, trying to build an AE model derived from a base ACE model
<
pre>
twinAEModel <- mxModel( twinACEModel, name="twinAEModel",
manifestVars=selVars,
latentVars=aceVars,
# This next line doesn't work if used
# mxPath(from=c("C1","C1"), to=c("bmi1","bmi2"), arrows=1, free=FALSE, values=0, label="cfixed")
# I thought that meant all paths in a single call have to found in one submodel... but...
# This also doesn't work
# mxPath(from="C1", to="bmi1", arrows=1, free=FALSE, values=0, label="cfixed"),
# mxPath(from="C2", to="bmi2", arrows=1, free=FALSE, values=0, label="cfixed")
It seems that ALL of the paths need to be rebuild, even the ones that are not being touched....
In the demo "UnivariateTwinAnalysis_PathRaw", twinACEModel is a model that contains two nested submodels. So in fact the following statement from the demo is incorrect:
Wait twinAEModel is a RAM model??? This implies that an automatic RAM objective function is created, over-writing the algebra objective from twinACEModel. OK, I don't know what is the intent of the demo.
I think I've figured out the intent of the demo. I'm checking in a fix in a few minutes. It would be helpful to have some omxCheckCloseEnough() statements at the end of the script to catch these types of errors.
I see why the demo writer called the c path "cfixed", instead of leaving it called "c" - which is what it is... trying this instead gives an error
mxPath(from=c("A1","C1","E1"), to="bmi1", arrows=1, free=c(T,F,T), values=c(.6,0,.6), label=c("a","c","e")),
# Running twinACE (should be AE - they forget to change the internal name...)
# Error: The label 'c' has been assigned to a free parameter and a fixed value!
So the bug is that when a path is updated, the question of whether to let the new output of mxPath squash the old path when that involves side effects on other paths (like fixing them) has not been resolved (at least as of build 725)
Given previous discussion here that mxPath() overwrites existing paths, clearly setting the path to fixed should just go ahead and set paths of the same name in other groups in the container to fixed also.
The bug was fixed in revision 723. Make sure your local repository is identical to the subversion repository by running "svn status". That should report no differences. If you see something like "M UnivariateTwinAnalysis_PathRaw.R" then you need to delete your local copy and then run "svn update" again. In the corrected demo, there is no free parameter named 'cfixed' because the free parameter 'c' from the ACE model is replaced in the AE model with a fixed values named 'c'. In the broken demo, the path "cfixed" was placed in the super-model and the 'c' free parameters in the submodels were not deleted. Hence the error about assigning 'c' to a free parameter and a fixed value.
OK, I have that now - i must have touched the old file and stopped it updating.
Is there a way to talk to the supermodel (hereafter known as "Elle"), and get it to direct mxPath requests to all sub-models?
Usecase: Often something done to one submodel would need to doing to all submodels, and in a complex design there might be 7 of these, so it would be handy to be able to say "do this everywhere"
# Places path in supermodel and all submodels,
# if-and-only-if a model is RAM type and contains
# manifest or latent variables for the 'from' and 'to' fields
# of the given path.
pathClobberRecursive <- function(model, path) {
if (is(model, "MxRAMModel")) {
from <- path$from
to <- path$to
vars <- union(model@manifestVars, model@latentVars)
if (all(from %in% vars) && all(to %in% vars)) {
model <- mxModel(model, path)
}
}
model@submodels <- lapply(model@submodels, pathClobberRecursive, path)
return(model)
}
I would not make this a part of the OpenMx API. It would be akin to handing the users a loaded shotgun and saying "don't hurt yourself".
Given that the demo writer clearly thought that was what would happen, and I did too, maybe give us that gun, but put a safety catch on it: with clobber=FALSE the default.
PS: You really know both your R and recursive programming to punch out that function so quickly! I didn't see how "model<-mxModel(m, p)" was doing anything other than restating the problem until glancing down to the call to self... Nice work.
PPS: Its this kind of thing that was impossible in oldMx: I think a library of helper function like this will accumulate quickly!
PPPS: Does leaving stuff like paths lying around in supermodels have any nasty side-effects?
If TRUE, elements listed in this statement are added to the original model. If FALSE, elements listed in this statement are removed from the original model.
That seems back to front. Surely if remove is true, statements are removed?
help for ?mxModel notes that if you provide a model as the first parameter of mxModel(), then "all elements of that model are placed in the resulting MxModel object"
Given that, I assume that given an input "share" which has type=RAM
mxModel(share,
mxPath(from="A1", to="A2", arrows=2, free=FALSE, values=1),
mxData(mzfData, type="raw"),
type="RAM", name="MZ")
It is redundant to re-specify the type now, yes? Seems to work leaving it out.
And just to followup, if you create a path than already exists in the base model, it is overwritten?
Tried this and it seemed to work (specifying all paths in mz, then making dz simply over-write the A1<->A2 path as FIXED, 0.5)
<
pre>
Fit ACE Model with RawData and Path-Style Input
mz <- mxModel("MZ", type="RAM",
manifestVars=selVars,
latentVars=aceVars,
mxPath(from=aceVars, arrows=2, free=FALSE, values=1),
mxPath(from="one", to=aceVars, arrows=1, free=FALSE, values=0),
mxPath(from="one", to=selVars, arrows=1, free=TRUE, values=20, labels= c("mean","mean")),
mxPath(from=c("A1","C1","E1"), to="bmi1", arrows=1, free=TRUE, values=.6, label=c("a","c","e")),
mxPath(from=c("A2","C2","E2"), to="bmi2", arrows=1, free=TRUE, values=.6, label=c("a","c","e")),
mxPath(from="C1", to="C2", arrows=2, free=FALSE, values=1),
mxPath(from="A1", to="A2", arrows=2, free=FALSE, values=1),
mxData(mzfData, type="raw") )
twinACEModel <- mxModel("twinACE",
mz,
mxModel(mz, name="DZ",
mxPath(from="A1", to="A2", arrows=2, free=FALSE, values=.5),
mxData(dzfData, type="raw")
),
mxAlgebra(MZ.objective + DZ.objective, name="twin"),
mxAlgebraObjective("twin")
)
Yes, it is redundant to re-specify the type. When the first argument to mxModel is a model, then a copy of that model is used as the starting point for the model that will be returned from the function (pass by value). Also, if a path is specified with the same "from" and "to" fields as a path that already exists, it will overwrite the existing path.
type="x" is there so that other path-able model formulations can be used. For instance, Paras is looking at implementing type="LISREL". Until there is a second model type, type= is redundant. Don't rely on it remaining so.
I think the context here was not not "redundant as in doesn't get used" but rather "redundant" in that it will be imported from the model passed in as parameter 1, so setting it again is ... overkill"
Is that correct? I think already you can't leave out type="RAM", and expect to set paths... I bumped into this with a supermodel (container) that had no type set, and when I tried to drop paths it said "model type does not take paths"
I see. You are correct. It doesn't hurt to set type="RAM" twice, but is unnecessary. However, we do insist that you set type="RAM" if you plan to use mxPath. One might consider using mxPath as implying type="RAM", and while that could work for the moment, it will break in the long run, so we have insisted on people being explicit about type="RAM" now so that their code won't break when type="LISREL" is implemented.
when you make a model containing models, I see that the new container does not know about the latentVars and manifestVars of its nestlings.
Questions:
2a: If it is too allow communication with the nestlings, then I think the super-model's latentVars and manifestVars should automatically updated to be the intersection of the nested models latentVars and manifestVars?
That way you can't get things out of whack.
Just for context, this arose for me in changing from this
to this
got
Error: The following are neither manifest nor latent variables: 'C1', 'C2'
Which then ran fine after I added manifestVars and latentVars to twinACEModel
FYI, the relevant preceding code is:
<
pre>
MZ <- mxModel("MZ", type="RAM",
manifestVars=selVars,
latentVars =aceVars,
mxPath(from=aceVars, arrows=2, free=FALSE, values=1),
mxPath(from="one", to=aceVars, arrows=1, free=FALSE, values=0),
mxPath(from="one", to=selVars, arrows=1, free=TRUE, values=20, labels= c("mean","mean")),
mxPath(from=c("A1","C1","E1"), to="bmi1", arrows=1, free=TRUE, values=.6, label=c("a","c","e")),
mxPath(from=c("A2","C2","E2"), to="bmi2", arrows=1, free=TRUE, values=.6, label=c("a","c","e")),
mxPath(from="C1", to="C2", arrows=2, free=FALSE, values=1),
mxPath(from="A1", to="A2", arrows=2, free=FALSE, values=1), # MZ correlation for T1 and T2
mxData(mzfData, type="raw")
)
Build DZ group based on MZ just change the data and A-coefficient
DZ = mxModel(MZ, name="DZ",
mxPath(from="A1", to="A2", arrows=2, free=FALSE, values=.5), # overwrite: value = .5 for DZ
mxData(dzfData, type="raw")
)
Make a super-model to contain both the MZ and DZ groups
twinACEModel <- mxModel("twinACE", type="RAM", # have to call this RAM, so it will accept paths later on
# oops, also need to add latent and manifest here, but have not yet
MZ, DZ,
mxAlgebra(MZ.objective + DZ.objective, name="twin"),
mxAlgebraObjective("twin") # the algebra we are trying to minimise
)
Script error and code bug?
DROP C not working in trunk/demo/UnivariateTwinAnalysis_PathRaw.R
Hi there,
I trying to build a univariate twin raw data script, and this prompts some questions.
In the original script the fit changes, but the values for C don't drop to 0 for the AE model.
in the ACE model, the three paths in each group are labelled label=c("a","c","e"), and then accessed here to compute A C and E:
Then in the AE model the labels are set to c("a","cfixed","e"))
Then there is a critical error in the script: the exact same a,c,e labels as before are used again to calculate A C and E for the AE model.
In addition to the error in the script code, isn't there also a bug?
BUG?: given that the C path has been overwritten by this:
Why doesn't this return an error: no path with that label?
given it should be (which does return C = exactly 0)
Bug in overwriting path with mxPath() in model?
I wrote a modified script for univariate ACE to AE... but the fit didn't change when dropping C.
The relevant code-chunk is this, trying to build an AE model derived from a base ACE model
<
pre>
twinAEModel <- mxModel( twinACEModel, name="twinAEModel",
manifestVars=selVars,
latentVars=aceVars,
# This next line doesn't work if used
# mxPath(from=c("C1","C1"), to=c("bmi1","bmi2"), arrows=1, free=FALSE, values=0, label="cfixed")
# I thought that meant all paths in a single call have to found in one submodel... but...
# This also doesn't work
# mxPath(from="C1", to="bmi1", arrows=1, free=FALSE, values=0, label="cfixed"),
# mxPath(from="C2", to="bmi2", arrows=1, free=FALSE, values=0, label="cfixed")
It seems that ALL of the paths need to be rebuild, even the ones that are not being touched....
this works
mxPath(from=c("A1","C1","E1"), to="bmi1", arrows=1, free=c(T,F,T), values=c(.6,0,.6), label=c("a","cfixed","e")),
mxPath(from=c("A2","C2","E2"), to="bmi2", arrows=1, free=c(T,F,T), values=c(.6,0,.6), label=c("a","cfixed","e"))
)
Is that a bug?
In the demo "UnivariateTwinAnalysis_PathRaw", twinACEModel is a model that contains two nested submodels. So in fact the following statement from the demo is incorrect:
What SHOULD be happening is the paths should be removed from each submodel.
Wait twinAEModel is a RAM model??? This implies that an automatic RAM objective function is created, over-writing the algebra objective from twinACEModel. OK, I don't know what is the intent of the demo.
I think I've figured out the intent of the demo. I'm checking in a fix in a few minutes. It would be helpful to have some omxCheckCloseEnough() statements at the end of the script to catch these types of errors.
hi Mike,
I see why the demo writer called the c path "cfixed", instead of leaving it called "c" - which is what it is... trying this instead gives an error
So the bug is that when a path is updated, the question of whether to let the new output of mxPath squash the old path when that involves side effects on other paths (like fixing them) has not been resolved (at least as of build 725)
Given previous discussion here that mxPath() overwrites existing paths, clearly setting the path to fixed should just go ahead and set paths of the same name in other groups in the container to fixed also.
The bug was fixed in revision 723. Make sure your local repository is identical to the subversion repository by running "svn status". That should report no differences. If you see something like "M UnivariateTwinAnalysis_PathRaw.R" then you need to delete your local copy and then run "svn update" again. In the corrected demo, there is no free parameter named 'cfixed' because the free parameter 'c' from the ACE model is replaced in the AE model with a fixed values named 'c'. In the broken demo, the path "cfixed" was placed in the super-model and the 'c' free parameters in the submodels were not deleted. Hence the error about assigning 'c' to a free parameter and a fixed value.
OK, I have that now - i must have touched the old file and stopped it updating.
Is there a way to talk to the supermodel (hereafter known as "Elle"), and get it to direct mxPath requests to all sub-models?
Usecase: Often something done to one submodel would need to doing to all submodels, and in a complex design there might be 7 of these, so it would be handy to be able to say "do this everywhere"
I would not make this a part of the OpenMx API. It would be akin to handing the users a loaded shotgun and saying "don't hurt yourself".
I like guns :-)
Given that the demo writer clearly thought that was what would happen, and I did too, maybe give us that gun, but put a safety catch on it: with clobber=FALSE the default.
PS: You really know both your R and recursive programming to punch out that function so quickly! I didn't see how "model<-mxModel(m, p)" was doing anything other than restating the problem until glancing down to the call to self... Nice work.
PPS: Its this kind of thing that was impossible in oldMx: I think a library of helper function like this will accumulate quickly!
PPPS: Does leaving stuff like paths lying around in supermodels have any nasty side-effects?
?MxModel tells us that remove is:
If TRUE, elements listed in this statement are added to the original model. If FALSE, elements listed in this statement are removed from the original model.
That seems back to front. Surely if remove is true, statements are removed?
Fixed.