Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have two tensors of arbitrary but equal rank n (and equal dimensions): A and B, and I want to get a third tensor of rank n + 1, C.

I want to do a element by element Join, so the element in A and the corresponding element in B are contracted into a list in C.

For example, with n = 2:

A = {{a[0,0],a[1,0]},{a[0,1],a[1,1]}};
B = {{b[0,0],b[1,0]},{b[0,1],b[1,1]}};

then:

C = {{ {a[0,0],b[0,0]} , {a[1,0],b[1,0]} },{ {a[0,1],b[0,1]} , {a[1,1],b[1,1]} }}

I think it might be doable with some combination of Inner and List, but I'm not sure.

share|improve this question
    
Note: C is a built-in symbol in System` and it's not wise to assign/modify it unless absolutely necessary. –  rm -rf Jan 7 '13 at 23:19
    
Sorry, I was using A, B and C as example variables. –  Andrew Spott Jan 7 '13 at 23:20
1  
This is very strongly related, although the way the two questions are worded, they're entirely different mathematica.stackexchange.com/q/17291/5 –  rm -rf Jan 7 '13 at 23:35
add comment

5 Answers

Here are a couple of possibilities.

MapThread[Riffle[{#1}, {#2}] &, {aA, bB}, 2]

(* Out[64]= {{{a[0, 0], b[0, 0]}, {a[1, 0], b[1, 0]}}, {{a[0, 1], 
   b[0, 1]}, {a[1, 1], b[1, 1]}}} *)

Transpose[ArrayFlatten[{aA, bB}], {3, 1, 2}]

(* Out[72]= {{{a[0, 0], b[0, 0]}, {a[1, 0], b[1, 0]}}, {{a[0, 1], 
   b[0, 1]}, {a[1, 1], b[1, 1]}}} *)

Another that I like less:

Map[Thread, Thread[{aA, bB}]]

--- edit ---

Actually that second one should just be

Transpose[{aA, bB}, {3, 1, 2}]

The ArrayFlatten was not needed in this case (it can be useful somethimes though). And in case it was not clear, the lists are:

aA = {{a[0, 0], a[1, 0]}, {a[0, 1], a[1, 1]}};
bB = {{b[0, 0], b[1, 0]}, {b[0, 1], b[1, 1]}};

--- end edit ---

share|improve this answer
add comment

Here's a fairly simple way of doing it (ignore the front end's syntax warning):

Function[, {##}, Listable][A, B]
(* {{{a[0, 0], b[0, 0]}, {a[1, 0], b[1, 0]}}, 
    {{a[0, 1],  b[0, 1]}, {a[1, 1], b[1, 1]}}} *)
share|improve this answer
    
Why does that work? It is very interesting, but what if I want to make a[0,0] a list as well? –  Andrew Spott Jan 7 '13 at 23:48
1  
If you consider element-wise multiplication A B, that is possible because of the Listable attribute of Times. In other words, it threads over lists in its arguments. What I've done above is similar – it creates a pure function that "joins" the arguments ({#}) and threads it over lists (Listable). The omitted argument is taken as Null. I don't understand what you mean by wanting to make a[0,0] a list as well, as it's no longer element-wise join, as you wanted. –  rm -rf Jan 7 '13 at 23:55
    
+1. You are too fast, I am running out of tricks :-) –  Leonid Shifrin Jan 8 '13 at 0:01
add comment

Maybe a pedagogical alternative

(A + B) /. Plus -> List
share|improve this answer
2  
I don't think this will work in general. Think about what happens if the elements of A and B are numbers. –  m_goldberg Jan 8 '13 at 1:05
    
sure. as mentioned: it is just pedagogical in that sense that it is easy to understand and you don't have to use Function with a Null argument. –  Rolf Mertig Jan 8 '13 at 9:34
add comment

From your comment "what if I want to make a[0,0] a list as well?" I think Daniel's Transpose method is the way to go but the second parameter was never generalized. I believe you could use:

elementJoin[a_, b_] := 
  Transpose[{a, b}, RotateRight @ Range @ ArrayDepth @ {a, b}]

elementJoin[
 {1, 2, 3},
 {4, 5, 6}
]
{{1, 4}, {2, 5}, {3, 6}}
elementJoin[
 {{1, 2, 3}, {11, 22, 33}},
 {{4, 5, 6}, {44, 55, 66}}
]
{{{1, 4}, {2, 5}, {3, 6}}, {{11, 44}, {22, 55}, {33, 66}}}
elementJoin[
 {{{a1, a2, a3}, {b1, b2, b3}, {c1, c2, c3}}, {11, 22, 33}},
 {{{a4, a5, a6}, {b4, b5, b6}, {c4, c5, c6}}, {44, 55, 66}}
]
{{{{a1, a2, a3}, {a4, a5, a6}}, {{b1, b2, b3}, {b4, b5, b6}},
    {{c1, c2, c3}, {c4, c5, c6}}}, {{11, 44}, {22, 55}, {33, 66}}}

Note that this last output is not the same as that produced by R.M's Listable function:

Function[, {##}, Listable][
 {{{a1, a2, a3}, {b1, b2, b3}, {c1, c2, c3}}, {11, 22, 33}},
 {{{a4, a5, a6}, {b4, b5, b6}, {c4, c5, c6}}, {44, 55, 66}}
]
{{{{a1, a4}, {a2, a5}, {a3, a6}}, {{b1, b4}, {b2, b5}, {b3, b6}}, {{c1, c4},
 {c2, c5}, {c3, c6}}}, {{11, 44}, {22, 55}, {33, 66}}}

Choose according to your needs.

share|improve this answer
add comment

In the spirit of Rolf Mertig's answer we can abuse a system function with the attribute Listable to effect our join. By simultaneously using an invalid syntax we can avoid undesired evaluation. I chose Re:

threadJoin = Quiet[Re @ ##] /. Re -> List &;

Now:

threadJoin[
 {1, 2, 3},
 {4, 5, 6}
]
{{1, 4}, {2, 5}, {3, 6}}
threadJoin[
 {{a[0, 0], a[1, 0]}, {a[0, 1], a[1, 1]}},
 {{b[0, 0], b[1, 0]}, {b[0, 1], b[1, 1]}},
 {{c[0, 0], c[1, 0]}, {c[0, 1], c[1, 1]}}
]
{{{a[0, 0], b[0, 0], c[0, 0]}, {a[1, 0], b[1, 0], c[1, 0]}},
   {{a[0, 1], b[0, 1], c[0, 1]}, {a[1, 1], b[1, 1], c[1, 1]}}}
threadJoin[
 {{{a1, a2, a3}, {b1, b2, b3}, {c1, c2, c3}}, {11, 22, 33}},
 {{{a4, a5, a6}, {b4, b5, b6}, {c4, c5, c6}}, {44, 55, 66}}
]
{{{{a1, a4}, {a2, a5}, {a3, a6}}, {{b1, b4}, {b2, b5}, {b3, b6}}, {{c1, c4},
    {c2, c5}, {c3, c6}}}, {{11, 44}, {22, 55}, {33, 66}}}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.