Thu, 08/27/2009 - 16:44

There has been some talk recently of simplifying the MxAlgebra interface in two regards. It would be convenient to specify constant values or matrices in an MxAlgebra statement, without having to explicitly declare a separate MxMatrix that contains constant values. It would also be convenient to specify free parameters in an MxAlgebra statment, without having to explicitly declare a separate 1 x 1 MxMatrix that contains the free parameter. We have been referring to these proposed changes as constant substitution and free parameter substitution, respectively.

So here's how these substitutions are actually going to work. Assume 'foo' is either an argument to some function inside an MxAlgebra expression, or 'foo' is an operand to some operator inside an MxAlgebra expression. In the following order, check the following cases:

(1) Is 'foo' a constant scalar or matrix? If yes, then perform constant substitution.

(2) Otherwise is 'foo' a named entity or a free parameter? By named entity, I mean is it a reference to an MxAlgebra, MxMatrix, or MxObjectiveFunction. Named entities and free parameters cannot have overlapping names. If 'foo' is a named entity, then business as usual. If 'foo' is a free parameter, then perform free parameter substitution by creating a 1 x 1 MxMatrix.

(3) Otherwise is 'foo' a global variable? If yes, and foo refers to a scalar, a vector, or a matrix, then perform constant substitution. Vectors are converted to n x 1 matrices (try as.matrix(), it's the default behavior).

(4) Otherwise, 'foo' is an unknown reference and we have an error.

So the order is:

- constant values
- named entities / free parameters
- global variables

Hi mike, this will be great!

How are items meeting criteria (1) written., i.e. how do you write an inline matrix?

Ah whoops. I forgot that R doesn't have literal forms for vector or matrix values. So there are two alternatives (at least) to amend the proposed. In the first alternative, criteria (1) is made more restrictive such that only literal scalar values are allowed. In the first alternative, constant vectors or matrices must be introduced by a global variable. In the second alternative, we treat the functions "c" and "matrix" as special cases. Anytime the MxAlgebra parser encounters one of these functions, it evaluates that subexpression and uses the vector or matrix that is returned. The downside to the second alternative is that users who put free parameters inside a c() or matrix() expression will not get what they expect.

Overall, I like the proposal and I think it will be welcomed by others.

I would like to propose a slightly more restrictive version that might serve almost as well. As you point out, the union of the namespace of named entities as we currently think of them and the namespace of free parameters must now be constrained to be unique.

(SMB 1) If foo is a scalar constant (i.e., not a named variable in R, not matrix(3,1,1) or c(1)), but an actual number typed into the expression), perform constant substitution.

(SMB 2) If foo is a "reasonable" named entity in the current mxModel namespace (i.e., something that evaluates to a matrix or scalar, e.g. a parameter, a named column from mxData, an mxMatrix, an mxAlgebra, an mxObjectiveFunction) then perform free parameter substitution by creating the appropriately sized matrix (1x1 for parameters, and nxm for mxMatrix or mxAlgebra, etc.).

(SMB 3) If a global variable evaluates to (a) a scalar numeric or (b) a matrix of scalar numerics, then perform constant substitution. Inline c() statements throw an error since it is unclear whether they are row or column vectors. Inline matrix() statements are ok if they evaluate to a matrix of numerics. R matrices can have elements of type "factor" or "string", and these must throw an error.

(SMB 4) Everything else throws an error.

Thus, if A is a variable in the R namespace and A is a named entity in the OpenMx namespace, the A in OpenMx takes precedence.

Also, Tim Bates has just proposed a special syntax for matrices. I would argue strongly against that. We should expect people to use R syntax. If someone else wants to write some other parser for creating R matrices of numerics, that's fine. But it isn't our job.

The whole idea here is mainly to simplify the use of things that are already in an mxModel namespace.

I agree with all of Steve's comments, except that I would strike out the special case for matrix() expressions. I'm sorry I suggested it. The suggestion violates the principle of least surprise. It is too easy to produce a counter-intuitive situation.

This does not produce a 5 x 5 matrix of the free parameter 'foo', but produces a 5 x 5 matrix of 5's. To reiterate, I support no special cases for function calls inside a MxAlgebra expression. The proposal is strictly limited to operands and function arguments.

Agreed. We must exclude R functions (such as matrix) or overload them since R functions won't know about the OpenMx namespace. At least for now, it seems to me to be a bad idea to overload matrix().

If you want a matrix use mxMatrix(). I can live with that.

Most of the utility is lost if inline matrices are disallowed, so good to avoid that.

If users have to write a global for everything, then this also decrases utility.

The use for inline is nearly always going to be quite small objects: 1*1s, etc.

Rather than making c and matrix special cases, I would vote for creating a literal form for matrices and special casing that.

Square-braces around a comma and semi-colon delimited list is compact and easy to read, and straight forward to write a parser for, I think:

[a,b;c,d] --> matrix(c(a,b,c,d), nrow=2)

IMHO, having Rish matrices inline might make the algebras quite unreadable/hard to maintain for most people.