Hi julia-users, I've recently stumbled over Julia and wanted to give it a try.
To assess it's speed, I've implemented another micro-benchmark, namely a version of Matlab's magic() function that generates magic squares. Since I have no experience writing optimal Julia code, I started off with literal translations of two different implementations - Matlab's and the one from magic_square.py from PyPy, which is an optimized version for NumPy. I then timed the calculation of all magic squares from N=3 to N=1000. The table from Julia's homepage suggests that in most cases, it is significantly faster than Python and Matlab. In my case, it's significantly slower, which is somehow disappointing ;) My question now is: Can the implementation be optimized to outperform the other two? *The times:* Julia, Matlab version: elapsed time: 18.495374216 seconds (13404087428 bytes allocated, 12.54% gc time) Julia, Python version: elapsed time: 8.107275449 seconds (13532473792 bytes allocated, 26.99% gc time) Matlab: Elapsed time is 4.994960 seconds. Python: 1 loops, best of 3: 2.09 s per loop My test machine is a 4 Core i7-4600 Notebook with 2.1 GHz and 8 GiB RAM, running a current Linux Mint and Julia 0.3 stable. To be fair, Python does not seem to gc during this loop (disabling gc doesn't alter the time here), so one should compare with 8.1 s * (1.-.2699) = 5.91 s for Julia. That's still much slower than Python. (By the way, even Octave only needs 4.46 seconds.) If I translate the matrices in magic_python to account for column-major storage, the execution time does not significantly improve. *The code:* Matlab: tic; arrayfun(@magic, 3:1000, 'UniformOutput', false); toc IPython: import magic_square; %timeit [ magic_square.magic(x) for x in range(3, 1001) ]; Julia: I've uploaded the code to a Gist at https://gist.github.com/phillipberndt/2db94bf5e0c16161dedc and will paste a copy below this post. Cheers, Phillip function magic_matlab(n::Int64) # Works exactly as Matlab's magic.m if n % 2 == 1 p = (1:n) M = n * mod(broadcast(+, p', p - div(n+3, 2)), n) + mod(broadcast(+, p', 2p - 2), n) + 1 return M elseif n % 4 == 0 J = div([1:n] % 4, 2) K = J' .== J M = broadcast(+, [1:n:(n*n)]', [0:n-1]) M[K] = n^2 + 1 - M[K] return M else p = div(n, 2) M = magic_matlab(p) M = [M M+2p^2; M+3p^2 M+p^2] if n == 2 return M end i = (1:p) k = (n-2)/4 j = convert(Array{Int}, [(1:k); ((n-k+2):n)]) M[[i; i+p],j] = M[[i+p; i],j] i = k+1 j = [1; i] M[[i; i+p],j] = M[[i+p; i],j] return M end end @vectorize_1arg Int magic_matlab function magic_python(n::Int64) # Works exactly as magic_square.py (from pypy) if n % 2 == 1 m = (n >> 1) + 1 b = n^2 + 1 M = reshape(repmat(1:n:b-n, 1, n+2)[m:end-m], n+1, n)[2:end, :] + reshape(repmat(0:(n-1), 1, n+2), n+2, n)[2:end-1, :]' return M elseif n % 4 == 0 b = n^2 + 1 d = reshape(1:b-1, n, n) d[1:4:n, 1:4:n] = b - d[1:4:n, 1:4:n] d[1:4:n, 4:4:n] = b - d[1:4:n, 4:4:n] d[4:4:n, 1:4:n] = b - d[4:4:n, 1:4:n] d[4:4:n, 4:4:n] = b - d[4:4:n, 4:4:n] d[2:4:n, 2:4:n] = b - d[2:4:n, 2:4:n] d[2:4:n, 3:4:n] = b - d[2:4:n, 3:4:n] d[3:4:n, 2:4:n] = b - d[3:4:n, 2:4:n] d[3:4:n, 3:4:n] = b - d[3:4:n, 3:4:n] return d else m = n >> 1 k = m >> 1 b = m^2 d = repmat(magic_python(m), 2, 2) d[1:m, 1:k] += 3*b d[1+m:end, 1+k:m] += 3*b d[1+k, 1+k] += 3*b d[1+k, 1] -= 3*b d[1+m+k, 1] += 3*b d[1+m+k, 1+k] -= 3*b d[1:m,1+m:n-k+1] += b+b d[1+m:end, 1+m:n-k+1] += b d[1:m, 1+n-k+1:end] += b d[1+m:end, 1+n-k+1:end] += b+b return d end end @vectorize_1arg Int magic_python print("Matlab version: ") @time magic_matlab(3:1000) print("Python version: ") @time magic_python(3:1000)