There and back again: A Matlab array's tale by Bob Turner

Some talk the other day about porting and interoperability between Matlab and Python, so I thought I'd investigate passing arrays back and forth...
I'm doing this (against Mathworks advice) in an Anaconda environment. However, starting Matlab from the Anaconda command prompt seemed to work fine.
pyversion
version: '3.7' executable: 'C:\A_is_for\Anaconda3\python.exe' library: 'C:\A_is_for\Anaconda3\python37.dll' home: 'C:\A_is_for\Anaconda3' isloaded: 0
Matlab version is:
version
ans = '9.6.0.1174912 (R2019a) Update 5'
My plan, here, is to make a big array in Matlab, convert it to a Python numpy array, do some manipulation of it (transpose it a couple of times) and then turn it back into a Matlab array. By way of an experiment, I'll time each step.
Firstly, we make a Matlab array of random numbers:
tic;
ml=rand(1e4,'double');
toc;
Elapsed time is 0.955807 seconds.
Next, out of curiosity, we do the same thing in Python:
tic;
np=py.numpy.random.rand(int8(1e4),int8(1e4));
toc;
Elapsed time is 0.659253 seconds.
Surprisingly faster than Matlab. By a lot. Perhaps the array is being generated at a lower precision? Right at the bottom of this block we see that it's a float64 which I think is the same as a Matlab double:
np.dtype
ans =
Python dtype with properties: alignment: [1×1 py.int] base: [1×1 py.numpy.dtype] byteorder: [1×1 py.str] char: [1×1 py.str] descr: [1×1 py.list] fields: [1×1 py.NoneType] flags: [1×1 py.int] hasobject: 0 isalignedstruct: 0 isbuiltin: [1×1 py.int] isnative: 1 itemsize: [1×1 py.int] kind: [1×1 py.str] metadata: [1×1 py.NoneType] name: [1×7 py.str] names: [1×1 py.NoneType] ndim: [1×1 py.int] num: [1×1 py.int] shape: [1×0 py.tuple] str: [1×3 py.str] subdtype: [1×1 py.NoneType] type: [1×1 py.type] float64
I'll transpose the array twice in Matlab (which should tax the computer but give me the same variable out as I put in:
tic;
ml_t=ml';
ml_t=ml_t';
toc;
Elapsed time is 0.823703 seconds.
...which I can check like this:
isequal(ml,ml_t)
ans = logical
1
...and it is. Obviously. Next, I'll turn the Matlab array into a Python array (using numpy):
tic;
ml_np=py.numpy.array(ml);
toc;
Elapsed time is 0.191298 seconds.
Or by saving a .mat file and reloading:
py.importlib.import_module("scipy"); %needs scipy which is not imported by default
tic;
save("mlfile.mat","ml")
mlfile_dict=py.scipy.io.loadmat("mlfile.mat");
mlfile_np=mlfile_dict{'ml'};
toc;
Elapsed time is 20.511985 seconds.
isequal(ml_np,mlfile_np)
ans = logical
1
Fine, but slow.
Transpose twice as in Matlab:
tic;
ml_np=ml_np.transpose;
ml_np=ml_np.transpose;
toc;
Elapsed time is 0.003869 seconds.
Convert back to Matlab:
tic;
ml_np_ml=double(ml_np);
toc;
Elapsed time is 1.470973 seconds.
...and test that the variable that's been converted to Python, transposed twice and converted back to Matlab is unchanged:
isequal(ml,ml_np_ml)
ans = logical
1
Looks like it's survived the ordeal!
This is good news and suggests that calling Python from Matlab might be do-able.
What surprises me about this is that despite everything being called from Matlab, the Python operations seem to be going way faster. Could be I'm missing something crucial, here. Not generalisable! If so I'd love to hear about it at bob.turner.uk at gmail.com or @Bobatron on Twitter!