# Python NumPy For Your Grandma - 6.7 Challenge: Outer Product

Contents

## Setup

Calculate the element-wise outer product of two matrices, `A` & `B`.

``````import numpy as np

A = np.arange(10*3).reshape((10,3))
print(A)
## [[ 0  1  2]
##  [ 3  4  5]
##  [ 6  7  8]
##  [ 9 10 11]
##  [12 13 14]
##  [15 16 17]
##  [18 19 20]
##  [21 22 23]
##  [24 25 26]
##  [27 28 29]]
B = np.arange(10*5).reshape((10,5))
print(B)
## [[ 0  1  2  3  4]
##  [ 5  6  7  8  9]
##  [10 11 12 13 14]
##  [15 16 17 18 19]
##  [20 21 22 23 24]
##  [25 26 27 28 29]
##  [30 31 32 33 34]
##  [35 36 37 38 39]
##  [40 41 42 43 44]
##  [45 46 47 48 49]]
``````

## Solution 1

``````def outer_prod_broadcasting(A, B):
return A[...,None]*B[:,None]

## array([[[   0,    0,    0,    0,    0],
##         [   0,    1,    2,    3,    4],
##         [   0,    2,    4,    6,    8]],
##
##        [[  15,   18,   21,   24,   27],
##         [  20,   24,   28,   32,   36],
##         [  25,   30,   35,   40,   45]],
##
##        [[  60,   66,   72,   78,   84],
##         [  70,   77,   84,   91,   98],
##         [  80,   88,   96,  104,  112]],
##
##        [[ 135,  144,  153,  162,  171],
##         [ 150,  160,  170,  180,  190],
##         [ 165,  176,  187,  198,  209]],
##
##        [[ 240,  252,  264,  276,  288],
##         [ 260,  273,  286,  299,  312],
##         [ 280,  294,  308,  322,  336]],
##
##        [[ 375,  390,  405,  420,  435],
##         [ 400,  416,  432,  448,  464],
##         [ 425,  442,  459,  476,  493]],
##
##        [[ 540,  558,  576,  594,  612],
##         [ 570,  589,  608,  627,  646],
##         [ 600,  620,  640,  660,  680]],
##
##        [[ 735,  756,  777,  798,  819],
##         [ 770,  792,  814,  836,  858],
##         [ 805,  828,  851,  874,  897]],
##
##        [[ 960,  984, 1008, 1032, 1056],
##         [1000, 1025, 1050, 1075, 1100],
##         [1040, 1066, 1092, 1118, 1144]],
##
##        [[1215, 1242, 1269, 1296, 1323],
##         [1260, 1288, 1316, 1344, 1372],
##         [1305, 1334, 1363, 1392, 1421]]])
``````

## Solution 2

``````def outer_prod_einsum(A, B):
"""einsum() trick"""
return np.einsum('ij,ik->ijk',A,B)

outer_prod_einsum(A, B)
## array([[[   0,    0,    0,    0,    0],
##         [   0,    1,    2,    3,    4],
##         [   0,    2,    4,    6,    8]],
##
##        [[  15,   18,   21,   24,   27],
##         [  20,   24,   28,   32,   36],
##         [  25,   30,   35,   40,   45]],
##
##        [[  60,   66,   72,   78,   84],
##         [  70,   77,   84,   91,   98],
##         [  80,   88,   96,  104,  112]],
##
##        [[ 135,  144,  153,  162,  171],
##         [ 150,  160,  170,  180,  190],
##         [ 165,  176,  187,  198,  209]],
##
##        [[ 240,  252,  264,  276,  288],
##         [ 260,  273,  286,  299,  312],
##         [ 280,  294,  308,  322,  336]],
##
##        [[ 375,  390,  405,  420,  435],
##         [ 400,  416,  432,  448,  464],
##         [ 425,  442,  459,  476,  493]],
##
##        [[ 540,  558,  576,  594,  612],
##         [ 570,  589,  608,  627,  646],
##         [ 600,  620,  640,  660,  680]],
##
##        [[ 735,  756,  777,  798,  819],
##         [ 770,  792,  814,  836,  858],
##         [ 805,  828,  851,  874,  897]],
##
##        [[ 960,  984, 1008, 1032, 1056],
##         [1000, 1025, 1050, 1075, 1100],
##         [1040, 1066, 1092, 1118, 1144]],
##
##        [[1215, 1242, 1269, 1296, 1323],
##         [1260, 1288, 1316, 1344, 1372],
##         [1305, 1334, 1363, 1392, 1421]]])
``````

## Solution 3

``````def outer_prod_stride(A, B):
"""stride trick"""
a = A.shape[-1]
b = B.shape[-1]
d = A.strides[-1]
new_shape = A.shape + (b,)
As = np.lib.stride_tricks.as_strided(A, shape=new_shape, strides=(a*d, d, 0))
Bs = np.lib.stride_tricks.as_strided(B, shape=new_shape, strides=(b*d, 0, d))
return As * Bs

outer_prod_stride(A, B)
## array([[[   0,    0,    0,    0,    0],
##         [   0,    1,    2,    3,    4],
##         [   0,    2,    4,    6,    8]],
##
##        [[  15,   18,   21,   24,   27],
##         [  20,   24,   28,   32,   36],
##         [  25,   30,   35,   40,   45]],
##
##        [[  60,   66,   72,   78,   84],
##         [  70,   77,   84,   91,   98],
##         [  80,   88,   96,  104,  112]],
##
##        [[ 135,  144,  153,  162,  171],
##         [ 150,  160,  170,  180,  190],
##         [ 165,  176,  187,  198,  209]],
##
##        [[ 240,  252,  264,  276,  288],
##         [ 260,  273,  286,  299,  312],
##         [ 280,  294,  308,  322,  336]],
##
##        [[ 375,  390,  405,  420,  435],
##         [ 400,  416,  432,  448,  464],
##         [ 425,  442,  459,  476,  493]],
##
##        [[ 540,  558,  576,  594,  612],
##         [ 570,  589,  608,  627,  646],
##         [ 600,  620,  640,  660,  680]],
##
##        [[ 735,  756,  777,  798,  819],
##         [ 770,  792,  814,  836,  858],
##         [ 805,  828,  851,  874,  897]],
##
##        [[ 960,  984, 1008, 1032, 1056],
##         [1000, 1025, 1050, 1075, 1100],
##         [1040, 1066, 1092, 1118, 1144]],
##
##        [[1215, 1242, 1269, 1296, 1323],
##         [1260, 1288, 1316, 1344, 1372],
##         [1305, 1334, 1363, 1392, 1421]]])
``````