tags:

views:

76

answers:

2

I know that using the Insert menu, you can create a matrix with vertical and horizontal lines, but not a more generic partition, such as dividing a 4x4 matrix into 4 2x2 partitions. Nor, can MatrixForm do any sort of partitioning. So, how would I go about programmatically displaying such a partitioned matrix? I would like to retain the ability of MatrixForm to act only as a wrapper and not affect subsequent evaluations, but it is not strictly necessary. I suspect this would involve using a Grid, but I haven't tried it.

+2  A: 

So this is what I came up with. For a matrix M:

M = {{a, b, 0, 0}, {c, d, 0, 0}, {0, 0, x, y}, {0, 0, z, w}};

you construct two list of True/False values (with True for places where you want separators) that take two arguments; first the matrix and second a list of positions for separators.

colSep = Fold[ReplacePart[#1, #2 -> True] &, 
              Table[False, {First@Dimensions@#1 + 1}], #2] &;
rowSep = Fold[ReplacePart[#1, #2 -> True] &, 
              Table[False, {Last@Dimensions@#1 + 1}], #2] &;

Now the partitioned view using Grid[] is made with the use of Dividers:

partMatrix = Grid[#1, Dividers -> {colSep[#1, #2], rowSep[#1, #3]}] &;

This takes three arguments; first the matrix, second the list of positions for column dividers, and third the list of values for row dividers.

In order for it to display nicely you just wrap it in brakets and use MatrixForm:

MatrixForm@{partMatrix[M, {3}, {3}]}

Which does the 2by2 partitioning you mentioned.

Timo
I have to spend some time looking over how it works exactly, but it is certainly clever. Although, you do lose the nice feature of `MatrixForm` where you can use its results directly. Give me a couple of hours to be able to vote up again.
rcollyer
The `Dividers` option can just take a list of positions for the dividers too, and you can even use styles: `Grid[M, Dividers -> {{3 -> True}, {3 -> Red}}]`
Michael Pilat
Good call, the Fold jiggery I pulled there was really just a first attempt to get something going. If you coded a better version of partMatrix, you could have it optionally inherit the Dividers option notation.
Timo
To get back to the original problem tough (and maybe this could be a question in itself), is there a way to have an object in Mathematica that has a different and separate form when it's displayed from when it's evaluated?
Timo
@Michael, which can be readily accomplished via `Thread[{3,4}-> True]`, for instance. That eliminates the need for `colSep` and `rowSep` for divider specifications of the form: `{{index_ ..}, style_}`. Also, `{{index_, style_} ..}` could be dealt with easily via `Rule @@@ {{index_, style_} ..}`.
rcollyer
@Timo, definitely a separate question. Do you want to post it, or should I?
rcollyer
@rcollyer Go ahead, I don't have time right now and it's related to your problem anyways. Would be interesting to get a good answer to it, though I have doubts as to whether that sort of thing is possible.
Timo
$Timo, There are two separate questions here. The first is an object that displays differently than it's evaluated. That's easy - use `Interpretation` or its low-level equivalents. (See, eg, http://www.feyncalc.org/FeynCalcBook/). The second is to make a display wrapper like "*Form". This might involve a CellPrint...
Simon
+2  A: 

After playing around for far too long trying to make Interpretation drop the displayed form and use the matrix when used in subsequent lines, I gave up and just made a wrapper that acts almost exactly like MatrixForm. This was really quick as it was a simple modification of this question.

Clear[pMatrixForm,pMatrixFormHelper]
pMatrixForm[mat_,col_Integer,row_:{}]:=pMatrixForm[mat,{col},row]
pMatrixForm[mat_,col_,row_Integer]:=pMatrixForm[mat,col,{row}]

pMatrixFormHelper[mat_,col_,row_]:=Interpretation[MatrixForm[
    {Grid[mat,Dividers->{Thread[col->True],Thread[row->True]}]}],mat]

pMatrixForm[mat_?MatrixQ,col:{___Integer}:{},row:{___Integer}:{}]:=
  (CellPrint[ExpressionCell[pMatrixFormHelper[mat,col,row],
     "Output",CellLabel->StringJoin["Out[",ToString[$Line],"]:=//pMatrixForm"]]];
   Unprotect[Out];Out[$Line]=mat;Protect[Out];mat;)

Then the postfix command //pMatrixForm[#, 3, 3]& will give the requested 2x2 partitioning of a 4x4 matrix. It maybe useful to change the defaults of pMatrixForm from no partitions to central partitions. This would not be hard.

Simon
Actually, pMatrixForm should probably inherit the argument structure of Grid - then they can all be simply passed through. I might rewrite this later.
Simon
@Simon: There's a typo, the entire function body of `pMatrixForm` must be wrapped in parantheses. (You have the closing one, but not the opener.) That said, referencing the output via `Out[<line num>]` works as expected. But, setting `p = pMatrixForm[M, 3, 3]` sets `p` to `Null`. This is very close to what I was looking for.
rcollyer
Simon
Well shucks, now I have to add this question to my favorites :). Thank you Simon for a great piece of education.
Timo
@Simon, I'll have to play with it to see how that comes together. But, definitely a nice solution.
rcollyer