4
$\begingroup$

This question may be trivial, but I can't get past it for the life of me.

I have $n$ matrices of dimension $p_i \times N_i$, with $i$ indexing the $n$-set. I also have $n$ vectors of the appropriate length.

I'm looking to create a list of the inner products. This works (obviously):

MapThread[Dot[#1,#2]&,{nmats,nvecs}]

The problem comes in when I pass in lists of nmats. That is, I have $C$ copies of nmats stored in cnmats and want to collect the above for each. For some reason Mapping works,

MapThread[Dot[#1,#2]&,{#,nvecs}]&/@cnmats

but Threading doesnt

Thread[MapThread[Dot[#1,#2]&,{#,nvecs}]&[cnmats]]

Replacing MapThread with Table moves the error to Dot: Nonrectangular tensor encountered.

The error returned is:

Incompatible dimensions of objects at positions {2, 1} and {2, 2} of (MapThread expression);
dimensions are n and C

$C$ and $N_i$ are $O(10^5)$, $p$ is $O(1)$, so I favor Thread for the speed advantage.

Why can't I thread here? How can I implement this differently to benefit from threading?

$\endgroup$
2
  • $\begingroup$ Possible duplicates: (14121), (37274), (45240) $\endgroup$
    – Mr.Wizard
    Commented Feb 28, 2016 at 3:39
  • $\begingroup$ Thank you sir, this will help me brush up on Threading in mathematica. $\endgroup$
    – user30193
    Commented Mar 6, 2016 at 6:06

1 Answer 1

3
$\begingroup$

The issue here has been explained in the posts linked by Mr.Wizard: Thread doesn't have a Hold* attribute so the inner code i.e. MapThread[Dot[#1,#2]&,{#,nvecs}]&[cnmats] will evaluate before Thread begins to work.

I write this answer just to highlight a property of Thread, which has actually be mentioned but not emphasized in this answer, that is, like Module and Manipulate, the… er… structure to be Threaded must explicitly exists inside Thread.

This property isn't eye-catching because, as mentioned above, Thread doesn't hold its arguments so usually the structure to be Threaded will become explicit after automatic evaluation, but it'll easily show up once you tried to control the evaluation order. For example:

D[{x, y}, {x, y}]
(* Derivative[y, 0][List][x, y] *)

Thread@D[{x, y}, {x, y}]
(* Derivative[y, 0][List][x, y] *)

Thread@Unevaluated@D[{x, y}, {x, y}]
(* {1, 1} *)

xy = {x, y}; Thread@Unevaluated@D[xy, xy]
(* Derivative[y, 0][List][x, y] *)

Output of the fourth sample is the same as the first two, what happened? Let's Trace it:

Thread@Unevaluated@D[xy, xy] // Trace

enter image description here

apparently Thread doesn't "see" the {x, y} so D[xy, xy] is still D[xy, xy] afterwards.

To fix the problem, one need to adjust the evaluation order further, here are 2 approaches:

With[{xy = {x, y}}, Thread@Unevaluated@D[xy, xy]]
Clear@xy;
Hold@Thread@Unevaluated@D[xy, xy] /. xy -> {x, y} // ReleaseHold

Back to your problem, if you want to insist on Thread (will it really be faster?), then

With[{cnmats = cnmats}, 
 Thread[Unevaluated[MapThread[Dot[#1, #2] &, {#, nvecs}] &[cnmats]]]]

should work.

$\endgroup$
1
  • $\begingroup$ Thank you much! The speedup turned out to be 10%: not as much as I had hoped for. $\endgroup$
    – user30193
    Commented Mar 6, 2016 at 6:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.