# How can I reproduce the MatrixForm, NumberForm, XyzForm behavior?

I wish to write a function like MatrixForm, that affect only display but not evaluation, i.e. a function that automatically is stripped away from output.

More precisely I wish a MatrixForm-variant that collect the LCM of the denominators of the elements of the matrix out of the matrix.

Is this possible?

I think Interpretation, Defer, etc. combined with Row, MatrixForm doesn't fill exactly this need. This is the best I did.

PrettyMatrixForm[
m_ /; VectorQ[m, NumericQ] \[Or] MatrixQ[m, NumericQ]] :=
With[{lcm = LCM @@ (Denominator /@ Flatten[m])},
If[lcm === 1, MatrixForm[m],
With[{mm = m*lcm},
Interpretation[Row[{1/lcm, " \[Times] ", MatrixForm[mm]}], m]]
]]

PrettyMatrixForm[{{1/2, 1/4}, {2, 1/3}}]


EDIT. I wish to be able to write and evaluate something linke this in a cell, as I can do with MatrixForm.

{{1/2, 1/4}, {2, 1/3}} //PrettyMatrixForm
% * 2


EDIT 2 To be even more clear, I wish to reproduce this behavior of Mathematica Kernel.

In[1]:= MatrixForm[{{a,b},{c,d}}]

Out[1]//MatrixForm= a   b

c   d

In[2]:= Out[1]

Out[2]= {{a, b}, {c, d}}


As you can see the Kernel show Out[1]//MatrixForm i.e. MatrixForm[Out[1]] but store in Out[1] only the list {{a,b},{c,d}}. This happens for all XyzForm-like symbols, and obviously happens also in the Mathematica Front-End.

• You might want m instead of mm as the second argument to Interpretation, but otherwise I'm feeling a little dense this morning -- exact what is unsatisfactory about your attempt? – Michael E2 Jul 1 '14 at 14:16
• I don't have time to write a more complete explanation at the moment but the rawest way to do this is with custom MakeBoxes and MakeExpression definitions, and you can also use TemplateBox (which can be hooked to the stylesheet, too). The Notation package may meet your needs, but I personally find myself always using Make... manually. – mfvonh Jul 1 '14 at 14:53
• @MichaelE2 Yes, I fixed the code, thanks. What is unsatisfatcory? The fact I cannot take the output of this as a new input; Interpretation works only for copy-pasting, which is something I rarely use; yes, I can save the list in a symbol, but this add sometime confusion... – unlikely Jul 1 '14 at 15:06
• MatrixForm works the same way, doesn't it? (That's what it seems you're asking for, to me.) – Michael E2 Jul 1 '14 at 15:08
• I'd recommend you work through Jason Harris presentation on typesetting: library.wolfram.com/infocenter/Conferences/8010 – Mike Honeychurch Jul 1 '14 at 22:20

UPDATE

Nice work, OP, with $OutputForms. I did not know about that. Here is my take on a complete solution that takes advantage of that find, and adds input handling with MakeExpression. I can't think of a situation in which this would be superior to InterpretationBox for this problem, but it is helpful in more complex cases. If[ FreeQ[$OutputForms, pm = PrettyMatrixForm],
Unprotect@$OutputForms; AppendTo[$OutputForms, pm];
Protect@$OutputForms]; MakeBoxes[ PrettyMatrixForm[m_ /; MatrixQ[m, ExactNumberQ] \[Or] VectorQ[m, ExactNumberQ]], form_] ^:= With[ {lcm = LCM @@ (Denominator /@ Flatten@m)}, If[ lcm === 1, MakeBoxes[MatrixForm@m, form], TagBox[RowBox[ Riffle[ MakeBoxes[#, form] & /@ {1/lcm, MatrixForm[m*lcm]}, "\[Times]"]], "PrettyMatrix"]]]; MakeExpression[ TagBox[RowBox[{ c_, "\[Times]", m_ }], "PrettyMatrix"], form_] := MakeExpression[RowBox[{c, " ", m}], form]; PrettyMatrixForm[{{1/2, 1/4}, {2, 1/3}}] %  {{1/2, 1/4}, {2, 1/3}} (Notice, however, that PrettyMatrixForm only gets stripped when boxes are actually generated. The same code with a ; after the fist line will behave differently. This is the same as MatrixForm.) If you copy the PrettyMatrixForm output into a new cell and evaluate it, it will be rearranged before evaluation. {{1/2, 1/4}, {2, 1/3}} ORIGINAL POST The FrontEnd uses a system of boxes to represent expressions. Try typing this into a cell and then hitting Ctrl+Shift+E: matrix = {{a, b}, {c, d}}; matrix // ToBoxes  Cell[BoxData[ RowBox[{"{", RowBox[{ RowBox[{"{", RowBox[{"a", ",", "b"}], "}"}], ",", RowBox[{"{", RowBox[{"c", ",", "d"}], "}"}]}], "}"}]], "Output", CellChangeTimes->{3.613237646690503*^9}] You can hit the same key combination to close that view. This is what's going on under the hood, and Mathematica uses a variety of mechanisms to translate between what you're seeing in the two different views -- that is, between boxes and expressions. This can happen at every layer of evaluation subject to complex rules that are not important here. In general those rules will operate the way they intuitively ought to. We can see how an expression is translated into boxes using ToBoxes: matrix // ToBoxes  RowBox[{{,RowBox[{RowBox[{{,RowBox[{a,,,b}],}}],,,RowBox[{{,RowBox[{c,,,d}],}}]}],}}] Likewise, we can go the other direction: % // ToExpression  {{a, b}, {c, d}} Boxes are symbolically much more complex than their corresponding expressions, which is one reason they are stripped as part of evaluation: % // (tf = TreeForm[#, VertexLabeling -> False] &)  %%% // tf  MatrixForm changes the box structure: matrix // MatrixForm // ToBoxes  TagBox[RowBox[{(,,GridBox[{{a,b},{c,d}},RowSpacings->1,ColumnSpacings->1,RowAlignments->Baseline,ColumnAlignments->Center],,)}],Function[BoxForme$,BoxForme$]] And Mathematica has built-in rules that tell it to interpret this box pattern correctly: % // ToExpression  {{a, b}, {c, d}} I mentioned that this transformation is part of the evaluation procedure. ToBoxes and ToExpression transform and evaluate, which is usually what we want. At a lower level, however, you can also specify how Mathematica should transform box structures before evaluation. This enables you to rearrange these structures and define forms of notational equivalence. Compare: 1 + 2 // ToBoxes  3 1 + 2 // MakeBoxes  RowBox[{"1", "+", "2"}] Similarly, RowBox[{"1", "+", "2"}] // ToExpression  3 RowBox[{"1", "+", "2"}] // MakeExpression  HoldComplete[1 + 2] MakeBoxes will be applied whenever an expression is "rendered" in the FrontEnd, and Mathematica allows us to override arbitrary patterns. So we'll do: MakeBoxes[PrettyMatrixForm[m_], form_] ^:= With[ {lcm = LCM @@ (Denominator /@ Flatten@m)}, If[ lcm === 1, ToBoxes@MatrixForm@m, RowBox[ToBoxes /@ {1/lcm, "\[Times]", MatrixForm[m*lcm]}]]]; matrix = {{1/2, 1/4}, {2, 1/3}}; matrix // PrettyMatrixForm  We have only altered how this expression is rendered into boxes: % // InputForm  PrettyMatrixForm[{{1/2, 1/4}, {2, 1/3}}] For complicated cases you could define a corresponding set of rules using MakeExpression, but I think this situation can be handled more simply: PrettyMatrixForm /: head_[left___, PrettyMatrixForm[m_], right___] := head[left, m, right]; matrix // PrettyMatrixForm; %^2  {{1/4, 1/16}, {4, 1/9}} % // PrettyMatrixForm  • Thanks for your detailed presentation of boxes and related construct. And also for the interesting workaround using upvalues. When I can upvote I'll do. But I'm still interested to know it there is a way to reproduce the exact beahvior of bultin MatrixForm... – unlikely Jul 2 '14 at 8:08 • @unlikely This is essentially how MatrixForm works, and the behavior is fairly close. What behavior do you want that this does not provide? – mfvonh Jul 2 '14 at 12:54 • Please see my EDIT 2 to the question. – unlikely Jul 2 '14 at 13:35 • I upvoted already, but, in addition to Out[1] or % not working in a new input cell, consider mat = RandomInteger[{1, 5}, {2, 2}]/12 // PrettyMatrixForm, which displays as lists instead of in PrettyMatrixForm. I thought I had it down once, but I must have had a latent definition lurking in the kernel and I can't reproduce it. :( The output was even labeled Out[1]//PrettyMatrixForm=...but I'm not very good at this stuff. – Michael E2 Jul 2 '14 at 17:34 • @MichaelE2 (Who is good at this stuff? :P It's some of the most tedious crap you can do in Mathematica in my opinion.) Your example is a good one I hadn't thought about -- my upvalues hack isn't the best I see. I'll have to play with it some more. – mfvonh Jul 2 '14 at 19:11 I think I finally found the right way.$OutputForms is a list of the formatting functions that get stripped off when wrapped around the output.

$OutputForms= {InputForm,OutputForm,TextForm,CForm,Short,Shallow,MatrixForm,TableForm,TreeForm,FullForm,NumberForm,EngineeringForm,ScientificForm,QuantityForm,PaddedForm,AccountingForm,BaseForm,DisplayForm,StyleForm,FortranForm,MathMLForm,TeXForm,StandardForm,TraditionalForm}  With this approach, I understand that PrettyMatrixForm become a tagging symbol that doesn't transform its argument. Then, as explained by @tomfvonh (thanks again) we need to attach a MakeBoxes definition to PrettyMatrixForm. This is what I wrote and apparently work. MakeBoxes[PrettyMatrixForm[m_ /; MatrixQ[m, ExactNumberQ] \[Or] VectorQ[m, ExactNumberQ]], form_] ^:= With[{lcm = LCM @@ (Denominator /@ Flatten@m)}, If[lcm === 1, ToBoxes@MatrixForm@m, With[{boxes = ToBoxes@Row[{1/lcm, MatrixForm[m*lcm]}, " \[Times] "]}, InterpretationBox[boxes, m] ] ] ]; If[!MemberQ[$OutputForms, PrettyMatrixForm],
Unprotect[$OutputForms]; AppendTo[$OutputForms, PrettyMatrixForm];
Protect[$OutputForms]; ] PrettyMatrixForm[{{1/2, 1/4}, {2, 1/3}}] %*12  Probably we can do better with a little more knowledge about boxes, so any amendment is still appreciated. Another improvement will be to handle symbolic and radicals of rational on denominators... PrettyMatrixForm[m_ /; VectorQ[m, NumericQ] \[Or] MatrixQ[m, NumericQ]] := With[{lcm = LCM @@ (Denominator /@ Flatten[m])}, If[lcm === 1, MatrixForm[m], With[{mm = m*lcm}, Interpretation[Row[{1/lcm, " \[Times] ", MatrixForm[mm]}], m]]]]  You need to remember the unformatted input to PrettyMatrixForm so that the matrix is available for subsequent use since the formatted form is not directly useable. {{1/2, 1/4}, {2, 1/3}} // PrettyMatrixForm  %.%  (m = {{1/2, 1/4}, {2, 1/3}}) // PrettyMatrixForm m2 = m.m Alternatively, use PrettyMatrixForm in $Post

$Post = If[MatrixQ[#], PrettyMatrixForm[#], #] &; m = {{1/2, 1/4}, {2, 1/3}}  m2 = m.m  To clear $Post

$Post =.  • Thanks, yes remembering the unformatted input can help, but sometimes add confusion and is error-prone; while a % or %% is better... I need to investigate on$Post: internal MatrixForm is based on this? – unlikely Jul 1 '14 at 15:09
• after investigating a bit, I think your code (the \$Post method), while interesting, is not exactly what I'm searching for, mainly because force to use it everywhere along a session. I added some detail to my original question. – unlikely Jul 1 '14 at 18:47