In [1]:
%load_ext autoreload
%autoreload 2
%matplotlib inline
import numpy as np

Optimized mdot

Create some sample data first.


In [5]:
D = np.random.random((10000, 10))
A = np.random.random((10, 1000))
B = np.random.random((1000, 5))
C = np.random.random((5, 50))

In [6]:
from mdot import mdot, print_optimal_chain_order
from mdot import _mdot, _mdot_three

In [7]:
%timeit mdot(A, B, C, optimize=True)
%timeit np.dot(np.dot(A, B), C)
%timeit np.dot(A, np.dot(B, C))


10000 loops, best of 3: 53.3 µs per loop
10000 loops, best of 3: 50.7 µs per loop
100 loops, best of 3: 2.68 ms per loop

(AB)C is the optimal solution. mdot yields basically the same performace (plus some overhead).

Let's determine the optimal solution to use it later:


In [10]:
print_optimal_chain_order(D, A, B, C)
print_optimal_chain_order(D, A, B, C, names=list("DABC"))


np.dot(np.dot(M_0, np.dot(M_1, M_2)), M_3)
np.dot(np.dot(D, np.dot(A, B)), C)

Test 4 arguments


In [6]:
print "inline optimization:"
%timeit mdot(D, A, B, C, optimize=True)
print "precalculated optimal parens"
%timeit np.dot(np.dot(D, np.dot(A, B)), C)

%timeit np.dot(np.dot(np.dot(D, A), B), C)
%timeit np.dot(np.dot(D, A), np.dot(B, C))
%timeit np.dot(D, np.dot(A, np.dot(B, C)))
%timeit np.dot(D, np.dot(np.dot(A, B), C))
%timeit np.dot(np.dot(D, np.dot(A, B)), C)


inline optimization:
100 loops, best of 3: 5 ms per loop
precalculated optimal parens
100 loops, best of 3: 4.93 ms per loop
1 loops, best of 3: 200 ms per loop
1 loops, best of 3: 674 ms per loop
100 loops, best of 3: 7.23 ms per loop
100 loops, best of 3: 6.35 ms per loop
100 loops, best of 3: 4.93 ms per loop