Working on a mechanics problem, I stumbled on something peculiar:
Since Inner is a generalisation of Dot, it changes its behaviour depending upon the structure of the input lists.
Inner[f, {a, b}, {x, y}, g]
g[f[a, x], f[b, y]]
Pretty straight forward, right? Tuples drawn from the lists get inserted into f and all resulting expressions are input into g.
Now if we use two nested lists as input, the following happens:
Inner[f, {{a, b}, {c, d}}, {{w, x}, {y, z}}, g]
{{g[f[a, w], f[b, y]], g[f[a, x], f[b, z]]}, {g[f[c, w], f[d, y]], g[f[c, x], f[d, z]]}}
With some formatting applied:
Inner[f, {{a, b}, {c, d}}, {{w, x}, {y, z}}, g]//Column
{g[f[a, w], f[b, y]], g[f[a, x], f[b, z]]}
{g[f[c, w], f[d, y]], g[f[c, x], f[d, z]]}
Whereas I would expect an output like this:
Inner[f, {{a, b}, {c, d}}, {{w, x}, {y, z}}, g]
g[f[{a,b},{w,x}],f[{c,d},{y,z}]]
Is there something I'm missing? Is there a way to have Inner be agnostic about the heads of the expressions inside the lists? I already found the following workaround here:
Inner[f, Unevaluated /@ {{a, b}, {c, d}}, Unevaluated /@ {{w, x}, {y, z}}, g]
g[f[Unevaluated[{a, b}], Unevaluated[{w, x}]], f[Unevaluated[{c, d}], Unevaluated[{y, z}]]]
But, as stated, this seems like a crude workaround.
To sum up my main question: Is there a function which generalizes the behaviour I'm looking for? And wouldn't it make sense for Inner to take an optional argument to control the depth on which it operates?
Inner, "Inner[f,Subscript[list, 1],Subscript[list, 2],g,n] contracts index n of the first tensor with the first index of the second tensor". It also statesInner[f,{{a,b},{c,d}},{x,y},g]->{g[f[a,x],f[b,y]],g[f[c,x],f[d,y]]}, so it is not unexpected behavior. – Marius Ladegård Meyer Nov 16 '14 at 17:33