Output to preserve dot product

I am fairly new to Mathematica and I am faced with a problem. I tried to search for the solution but it seems that I don't know how to formulate the short search request.

I need to perform a matrix product of

g = -I*Pi {{I1[x], 0}, {0, I2[x]}}.{{1 + G[x].Gt[x], 2*G[x]}, {-2*G[x], -1 - Gt[x].G[x]}}


However, I know that all the entries are matrices themselves, so I would like the dot product to be preserved in the output, i.e. to get something like

{{-I \[Pi] (1 + G[x].Gt[x]).I1[x], -2 I \[Pi] I1[x].G[x]},
{2 I \[Pi] I2[x].G[x], -I \[Pi] (-1 - Gt[x].G[x]).I2[x]}}


as opposed to

{{-I \[Pi] (1 + G[x].Gt[x]) I1[x], -2 I \[Pi] I1[x] G[x]},
{2 I \[Pi] I2[x] G[x], -I \[Pi] (-1 - Gt[x].G[x]) I2[x]}}


Is there any way to do this in Mathematica? N.B.: I don't want to specify the entire form of G[x],Gt[x] and other matrices at this stage.

-
Eugene, it is best if you do not Accept an answer so quickly; I usually wait 24 hours to give everyone a chance to reply. You will often get more and sometimes better answers this way. –  Mr.Wizard Jun 18 '13 at 15:29
I added simplifying-expressions as this falls into a general and notoriously hard category with a lot of pitfalls. For the same reason, +1. –  rcollyer Jun 18 '13 at 15:38
–  Jens Jun 18 '13 at 17:21

Use Inner instead of Dot per Silvia, but it is not the whole story. In more complex expressions, though, there will be some simplification and you are likely to end up with terms like

0.(1 + G[x].Gt[x]) + (-I π I2[x]).(-2 G[x])


where the leading term is nonsensical. But, Dot does not know how to handle scalars. You could use Distribute, but it may cause more problems than it is worth:

Distribute[(-I π I2[x]).(-2 G[x]), Times, Dot]
(*
(-I).(-2) (-I).G[x] π.(-2)π.G[x] I2[x].(-2) I2[x].G[x]
*)


which is not all that pleasant to simplify. So, I'd suggest using the following

Inner[Dot, -I π {{I1[x], 0}, {0, I2[x]}},
{{1 + G[x].Gt[x], 2 G[x]}, {-2 G[x], -1 - Gt[x].G[x]}}] //.
{
Dot[a_?NumericQ, q_] | Dot[q_, a_?NumericQ] :> a q,
Dot[(a___?NumericQ) q_, p_] :> a q.p,
Dot[ q_, (a___?NumericQ) p_] :> a q.p,
Dot[(a___?NumericQ) q_, b___?NumericQ p_] :> a b q.p}
(*
{{-I π I1[x].(1 + G[x].Gt[x]), -2 I π I1[x].G[x]},
{2 I π I2[x].G[x], -I π I2[x].(-1 - Gt[x].G[x])}}
*)


which is most of the way towards where you want to go. The term in the lower right still poses problems in extracting the extra minus sign, but it may not be worth trying to add a rule to accommodate it.

-
Yeah, this is great! –  Eugene B Jun 18 '13 at 15:31
+1 this is how I'll do it. Though I would prefer define a myDot function which contains all the rules. –  Silvia Jun 18 '13 at 15:32
@Silvia absolutely reasonable. Self-contained code is a good thing. –  rcollyer Jun 18 '13 at 15:34
Generalized the Dot[0, _] rule to any number, so it will now catch the case: Dot[5, q]. –  rcollyer Jun 18 '13 at 17:10

What you're looking for is Inner with Dot playing the role of multiplication:

Inner[Dot, {{a, b}, {c, d}}, {{x, y}, {w, z}}]


{{a.x + b.w, a.y + b.z}, {c.x + d.w, c.y + d.z}}

-
Amazing! Thank you very much! –  Eugene B Jun 18 '13 at 15:20
@EugeneB hold up, there is more to the story. Give me a second to post my answer. –  rcollyer Jun 18 '13 at 15:20
@EugeneB You're welcome. But you might want to wait for some more time, in cases others will post better answers. –  Silvia Jun 18 '13 at 15:23
@rcollyer I'm looking forward to your more story. :) –  Silvia Jun 18 '13 at 15:24
@EugeneB my answer is up. –  rcollyer Jun 18 '13 at 15:29
show 1 more comment

You could define it as a function and defer the computations.

g[I1_, I2_, G_, Gt_] := -I*Pi ArrayFlatten[{{I1, 0}, {0, I2}}].ArrayFlatten[{{1 + G.Gt, 2 G}, {-2 G, -1 - Gt.G}}]


To get explicit results you can then later use g[I1[x], I2[x], G[x], Gt[x]].

-