# How to display operations on list elements

When applying some arithmetic operation on two lists, I'd like to display the actual operations between the elements of each list. For example, {1, 1} + {1, -1} would display {1 + 1, 1 - 1}.

With simple operations, I could just use Trace and pick out the part with the right form:

Trace[{1, 1} + {1, -1}, {_Plus, _Plus}]
(* {{1+1,1-1}} *)


However, this becomes really cumbersome in more complex operations. Even worse, some operations don't even show element-by-element operations within Trace.

Trace[{{1, 2}, {3, 4}}.{{5, 6}, {7, 8}}]
(* {{{1,2},{3,4}}.{{5,6},{7,8}},{{19,22},{43,50}}} *)


This is what I actually want to display:

Of course I could programmatically display the element operation of the matrix multiplication above, but I have to do the same for every other matrix operations.

My question is: Is there a straightforward way to display operations on elements of two lists? Please feel free to add your own examples and make it as general as you want to.

-
Related: (148), (37876) – Mr.Wizard Aug 16 '14 at 2:56
Thanks for TraceDepth! – seismatica Aug 16 '14 at 3:02
I notice you have not Accepted an answer to this. Does anything remain unaddressed to your satisfaction? Can I do anything to improve my answer? – Mr.Wizard Oct 6 '14 at 18:42

This might be "too direct" an answer, but you can try:

Inner[Inactive[Times], {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}, Inactive[Plus]] // MatrixForm


$\left( \begin{array}{cc} 1*5+2*7 & 1*6+2*8 \\ 3*5+4*7 & 3*6+4*8 \\ \end{array} \right)$

-
Very nice and succinct! I wonder if this could be achieved (perhaps with less terseness) in older MMA versions. – seismatica Aug 15 '14 at 20:04

For version 9 (and possibly older versions), you can use

Inner[Composition[Defer, Times], {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}] // MatrixForm


or

Inner[Defer[Times@##] &, {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}] // MatrixForm


or

Inner[Composition[HoldForm, Times], {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}] // MatrixForm


to get

-

The previous answers all use Inner to perform the specific operation of Dot, but these do not provide a general way to visualize results. I cannot provide a truly general way either but I feel that this has wider application:

SetAttributes[show, HoldFirst]
form[expr_] := expr /. m_ /; MatrixQ@Unevaluated@m :> MatrixForm[m]
show[expr_] :=
Row[{Defer[expr], Unevaluated[expr] /. n_?NumericQ :> Defer[n], expr}, "="] // form


Test:

{{1, 2}, {3, 4}}.{{5, 6}, {7, 8}} // show


In the simpler example a possible problem appears:

{1, 1} + {1, -1} // show


This is because of the behavior:

"foo" + "foo" + "foo"

3 "foo"


If this is unacceptable I shall have to include special handling.

Note: be aware of the automatic formatting that is applied even to held expressions; see:

-
Could you help me understand why Unevaluated[{{1, 2}, {3, 4}}.{{5, 6}, {7, 8}}] /. n_?NumericQ :> Defer[n] would display the intermediate result? – seismatica Aug 16 '14 at 3:15
@seismatica It makes all numeric objects inert and then evaluates it. This means that they are effectively treated as symbols or strings. This will not always produce the result you want but I think in sufficiently many cases to be useful it may. – Mr.Wizard Aug 16 '14 at 3:17
But what happens to the Unevaluated? Would it be erased by the ReplaceAll? To be honest I'm not quite sure what the difference is between Defer and Unevaluate, and let's not touch the variants of Hold. – seismatica Aug 16 '14 at 3:18
@seismatica You do not understand the way that Unevaluated works. I didn't either for a long time. Read the presentation I link here: (25308). See also this answer relating to the sister function Evaluate: (46753). These "functions" only affect the evaluation of the head directly surrounding them; one way to think about this is that ReplaceAll momentarily behaves as if it had a HoldFirst attribute. As soon as the replacement is complete evaluation continues normally. – Mr.Wizard Aug 16 '14 at 3:23
@seismatica Unevaluated and Defer do completely separate things. Unevaluated momentarily modifies the way a function evaluates its arguments, while Defer is a special kind of Hold that is removed during output formatting, resulting in an expression that will evaluate if given as input. I used it here so that you could copy, paste, and evaluate any part of the printed output. – Mr.Wizard Aug 16 '14 at 3:26

This is not an answer, but, based on chuy's solution, I want to show one of the advantages of the new V10 Inactive:

(x = Inner[Inactive[Times],
{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}},
Inactive[Plus]]) // MatrixForm


Activate[x, Times] // MatrixForm


Activate[x] // MatrixForm


-
Very nice demonstration of Inactive! – seismatica Aug 16 '14 at 3:20

Inspired by @Mr.Wizard's answer. This should work with both numbers and symbols:

ClearAll[elementDisplay]
SetAttributes[elementDisplay, HoldAll]
elementDisplay[f_[arg__List]] := f @@ Function[x, Defer[x], Listable]@{arg} // MatrixForm
elementDisplay[{{1, 2}, {a, b}}.{{5, 6}, {c, d}}]


ClearAll[listOpDisplay]
SetAttributes[listOpDisplay, HoldAll]
listOpDisplay[f_[arg__List]] :=
Row[{Defer[f[arg]], f @@ Function[x, Defer[x], Listable]@{arg},
f[arg]}, "="] /.
m_ /; MatrixQ@Unevaluated@m :> MatrixForm@m

listOpDisplay[{{1, 2}, {3, 4}}.{{5, 6}, {7, 8}}]


listOpDisplay[Cross[{1, 2, 3}, {1, 1/2, 1/3}]]


-