It seems numpy doesn't do any optimization but, perhaps more surprisingly, neither does Theano.
Here's a script to compare the two variations for each implementation. Output below.
import timeit
import numpy
import theano
import theano.tensor as tt
def main():
size = 1000
iterations = 1000
a = tt.matrix()
b = tt.matrix()
c = tt.matrix()
f1 = theano.function(inputs=[a, b, c], outputs=a * b + b * c)
f2 = theano.function(inputs=[a, b, c], outputs=(a + c) * b)
theano.printing.debugprint(f1)
theano.printing.debugprint(f2)
x = numpy.ones((size, size))
y = numpy.ones((size, size))
z = numpy.ones((size, size))
result = x * y + y * z
start = timeit.default_timer()
for _ in xrange(iterations):
result1 = x * y + y * z
assert numpy.all(result1 == result)
print timeit.default_timer() - start
start = timeit.default_timer()
for _ in xrange(iterations):
result2 = (x + z) * y
assert numpy.all(result2 == result)
print timeit.default_timer() - start
start = timeit.default_timer()
for _ in xrange(iterations):
result3 = f1(x, y, z)
assert numpy.all(result3 == result)
print timeit.default_timer() - start
start = timeit.default_timer()
for _ in xrange(iterations):
result4 = f2(x, y, z)
assert numpy.all(result4 == result)
print timeit.default_timer() - start
main()
I get the following output:
Elemwise{Composite{((i0 * i1) + (i1 * i2))}} [@A] '' 0
|<TensorType(float64, matrix)> [@B]
|<TensorType(float64, matrix)> [@C]
|<TensorType(float64, matrix)> [@D]
Elemwise{Composite{((i0 + i1) * i2)}} [@A] '' 0
|<TensorType(float64, matrix)> [@B]
|<TensorType(float64, matrix)> [@C]
|<TensorType(float64, matrix)> [@D]
9.19932313948
6.43367212255
4.15276831469
4.07725744595
So the manually optimized version is faster for both numpy and theano but the difference with Theano is smaller. The Theano computation graphs that are printing out show that Theano's optimizing compiler hasn't automatically improved the computation. Theano's version is faster overall though.
Note that these results can differ depending on the size of the matrices being operated on.