using mxMatrix

23 replies [Last post]
tbates's picture
Offline
Joined: 07/31/2009

Shouldn't matrices of type "Symm" only take one triangle of data? Otherwise you can do this: run runs fine, but sees asymmetrical values in the matrix

s <- mxMatrix(type="Symm", 3, 3,
c(FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE),
c(1, .9, .8, .8, 1, .8, .8, .8, 1),
c(NA, "free1", "free2", "free1", NA, "free3", "free2", "free3", NA))
s

jssteele's picture
Offline
Joined: 10/11/2009
Greetings all, I am not sure

Greetings all,
I am not sure this is the best place to post this but I have encountered a rather odd quirk with the mxMatrix command.
There is a shortcut in Chapter 3 of the documentation that uses 'T' & 'F' instead of the full 'TRUE' and 'FALSE' for the specification of the free parameters in the matrix. However this shortcut only works if the matrix is not of type 'Symm'. Otherwise it throws and error:

Error: Illegal number of elements (###) for free matrix in SymmMatrix constructor.

Changing the free parameter values to 'TRUE' & 'FALSE' fixes it, but this is allowed for matrices of type 'Full'.

==== Begin Example ====

# matrix specification error from documented shortcut in free matrix from Chapter 3.
# the first one works notice "TRUE" and "FALSE" are spelled out
s1 &lt;- mxMatrix(type="Symm", nrow=3, ncol=3,
	free=c(
		FALSE, TRUE, TRUE, 
		TRUE, FALSE, TRUE, 
		TRUE, TRUE, FALSE),
	values=c(
		1, .8, .8, 
		.8, 1, .8, 
		.8, .8, 1),
	labels=c(
		NA, "free1", "free2", 
		"free1", NA, "free3", 
		"free2", "free3", NA),
	name="S1");
 
# the second one does not, notice the use of "T" and "F" instead.
s2 &lt;- mxMatrix(type="Symm", nrow=3, ncol=3,
	free=c(
		F, T, T, 
		T, F, T, 
		T, T, F),
	values=c(
		1, .8, .8, 
		.8, 1, .8, 
		.8, .8, 1),
	labels=c(
		NA, "free1", "free2", 
		"free1", NA, "free3", 
		"free2", "free3", NA),
	name="S2");
 
# The error
Error: Illegal number of elements (###) for free matrix in SymmMatrix constructor.
 
# however the shortcut works for "Full" matrices
s3 &lt;- mxMatrix(type="Full", nrow=3, ncol=3,
	free=c(
		F, T, T, 
		T, F, T, 
		T, T, F),
	values=c(
		1, .8, .8, 
		.8, 1, .8, 
		.8, .8, 1),
	labels=c(
		NA, "free1", "free2", 
		"free1", NA, "free3", 
		"free2", "free3", NA),
	name="S3");
==== End Example ====
Oh and just an aside, I haven't been able to get the formatting the way I want it above, I tried <code> tags but it didn't preserve the whitespace, so I switched to <pre> tags... Minor nit I know.
Thats all for now.
-Joel

 

tbates's picture
Offline
Joined: 07/31/2009
Both ways work the same. Type

Both ways work the same.

Type "T" and "F" into R to see what they are set too... I'm guessing not to TRUE and FALSE

The 1-char codes are a very handy short-cut, but rely on the user not changing them to other values.

Caught me once (there's a post here to prove it). good practice from time to time to say:

if(T==TRUE & F==FALSE){

 

"OK"

} else {

"oops"

}

 

jssteele's picture
Offline
Joined: 10/11/2009
Hmmm, so it does. I wonder

Hmmm, so it does.

I wonder where I was encountering that error then? I was getting this on the 4th of this month, and I haven't updated any of the packages... strange.

Good to see it is working :)

Disregard my previous post.

-Joel

tbates's picture
Offline
Joined: 07/31/2009
an MxMatrix doesn't have a

an MxMatrix doesn't have a slot for its row or column count.

If we want to get the size of an mxMatrix, we should get the size of its values then get the dim of that?

dim(matrix@values)
--> [3,3]

mspiegel's picture
Offline
Joined: 07/31/2009
foo <- mxMatrix('Full', 3,

foo <- mxMatrix('Full', 3, 5)
nrow(foo)
ncol(foo)

tbates's picture
Offline
Joined: 07/31/2009
Thanks Michael!

Thanks Michael!

tbates's picture
Offline
Joined: 07/31/2009
cLabels = c( + "v1c1",

cLabels = c(
+ "v1c1", NA, NA,
+ "v2c1", "v2c2", NA,
+ "v3c1", "v3c2", "v3c3"
+ )
>
> cMatrix = mxMatrix("Lower", nrow=3, ncol=3, free=TRUE, values=.5, labels=cLabels, name="c") #
Error: Upper triangle of labels matrix in lower matrix 'c' is not all NAs!

The error message seems wrong or misleading. the upper triangle was all NAs.

Steve's picture
Offline
Joined: 07/30/2009
byrow=TRUE?

byrow=TRUE?

tbates's picture
Offline
Joined: 07/31/2009
hmm.. yes setting byrow=TRUE

hmm.. yes setting byrow=TRUE fixes that error... but sending just the lower triangle in row order works without altering byrow:

cLabels = c(
"v1c1",
"v2c1", "v2c2",
"v3c1", "v3c2", "v3c3"
)

cMatrix = mxMatrix("Lower", nrow=nVar, ncol=nVar, free=TRUE, values=.5, labels=cLabels, name="c")

So the default direction changes depending on whether you give a lower or a full set of values: if full, byrow=FALSE is the default, but if only a lower is given, then that fills as if byrow=TRUE?

mspiegel's picture
Offline
Joined: 07/31/2009
Umm, I tried the example you

Umm, I tried the example you just gave and the lower triangle of labels was populated by columns, just as you told it to be populated.

tbates's picture
Offline
Joined: 07/31/2009
Ouch. I see that now. Missed

Ouch. I see that now. Missed that bad bottom left entry.
Sorry for the false alarm.

I guess, then, I would like the default setting for by row to be TRUE.

Steve's picture
Offline
Joined: 07/30/2009
I've thought some about that.

I've thought some about that. And it is tempting. But nothing else in R has byrow=TRUE as a default. This is likely due to the dependence on CBLAS. But for whatever reason, R has byrow=FALSE defaults even when they don't make sense. (try using the defaults on write() on a data file and the read it back in with read.table() if you want some confusion)

Anyway, if people want to override defaults in R, they can do so. They can use the same methods to do so for OpenMx. But I think it would cause more confusion rather than less if we do things opposite of R's defaults.

mspiegel's picture
Offline
Joined: 07/31/2009
Based on the discussion of

Based on the discussion of today's developer meeting, a global option in R will be added to select the default behavior of the byrow argument. The standard value for this option will be FALSE. Any documentation on the website should assume the standard value of FALSE.

mspiegel's picture
Offline
Joined: 07/31/2009
As of revision 773, use

As of revision 773, use options('mxByrow' = TRUE) to change the default behavior of the byrow argument in the mxMatrix() function.

tbates's picture
Offline
Joined: 07/31/2009
I think in R you can find a

I think in R you can find a counter-example for any consistency :-)

In general, my argument (and yours too I think from what you say?) would be that our defaults should reflect the common settings that users want, not the common setting programmers chose.

Anyhow: I'll leave it to the hive mind, having made my buzz :-)

Off too add byrow=TRUE to everything...

Steve's picture
Offline
Joined: 07/30/2009
Yep, byrow=TRUE produces the

Yep, byrow=TRUE produces the correct result in either the NAs case or the lower triangular input case. No switching involved. If you want to input a vector into your matrices in this form:

> cLabels = c(
+ "v1c1",
+ "v2c1", "v2c2",
+ "v3c1", "v3c2", "v3c3"
+ )

always use byrow=TRUE.

tbates's picture
Offline
Joined: 07/31/2009
Q: Convert "Full" to

Q: Convert "Full" to "Lower"?

Is there a way in OpenMx to convert a matrix from Full to Lower?

I would like to be able to say mxMatrix(, "Lower", fullMatrixIPreparedEarlier)

But of course if you input the values matrix of a Full, it barfs on the non NA values in the upper triangle...

mspiegel's picture
Offline
Joined: 07/31/2009
At the moment, error checking

At the moment, error checking happens when you run the model. So in your example above, mxRun(mxModel(s)) will throw an error. If the user inputs only one triangle of data, then the lower triangle and upper triangle are populated with those values.

Steve's picture
Offline
Joined: 07/30/2009
This example points out that

This example points out that there are two classes of errors.

A. Some errors result in problems that are encapsulated within a single mxFoo function call.

B. Other errors are only evident when the entire model is evaluated together.

Tim Bates example is a Class A error. Catching Class A errors at their source is a service to the user since it localizes (both in space and time) their debugging.

mspiegel's picture
Offline
Joined: 07/31/2009
I've added error checking to

I've added error checking to the mxMatrix() function. I can see the possibility of the user wanting to create an incomplete and invalid matrix to use as a template. But the verification call is exactly one line, so its easy to reverse this decision.

tbates's picture
Offline
Joined: 07/31/2009
Thanks mike! In the same

Thanks mike!

In the same vein:

'Diag'
error if nrow != ncol. : "Symmetrical matrices must be square: You provided %i rows and %i columns!"
error if any values off the diagonal are free : "Error in matrix %name: No off-diagonal cells in an Diagonal matrix can be free"
error if any values off the diagonal are != 0 : "Error in matrix %name: All values off the diagonal of an Diagonal matrix must be 0"

'Iden'
error if nrow != ncol. : "Symmetrical matrices must be square: you provided %i rows and %i columns!"
error if any values are free : "Error in matrix %name: No cells in an Identity matrix can be free"
error if any values on the diagonal are != 1 : "Error in matrix %name: All values on the diagonal of an Identity matrix must be 1"
error if any values off the diagonal are != 0 : "Error in matrix %name: All values off the diagonal of an Identity matrix must be 0"

'Symm'
error if (nrow != ncol) : "Symmetrical matrices must be square: you provided %i rows and %i columns!"
done
error if any values are not mirrored in the upper and lower triangles
'Unit'
error if any values are free : "Error in matrix %name: No cells in a Unit matrix can be free"
error if any value != 1 : "Error in matrix %name: All values in a Unit matrix must be 1"
'Zero'
error if any values are free : "Error in matrix %name: No cells in a Zero matrix can be free"
error if any values != 0 : "Error in matrix %name: All values in a Zero matrix must be 0"

Steve's picture
Offline
Joined: 07/30/2009
Thanks for the fix. I think

Thanks for the fix. I think it's the right thing to do. In my opinion, the number of people helped by proximal error checking in this case will exceed the number of people frustrated. And the person who is frustrated will just say, "oh, I guess I couldn't fool the program that way." and maybe figure out that procedural model definition will help him/her get the same job done faster/easier anyway.

tbates's picture
Offline
Joined: 07/31/2009
Indeed: Much nicer to catch

Indeed: Much nicer to catch things when they occur - and much easier to give meaningful feedback
"You provided asymmetrical input to symmetrical matrix 'A' "

rather than
"Model parser got unexpected value, expected matrix" or similar.

Would it be desirable to throw an error on getting value array of length other than sigma(n) where n=1 to nrow?

Or is that just making life unnecessarily hard? It would make it impossible to commit the asymmetrical symm-matrix error.