Smop
Small Matlab to Python compiler
Install / Use
/learn @victorlei/SmopREADME
SMOP is Small Matlab and Octave to Python compiler.
SMOP translates matlab to python. Despite obvious similarities
between matlab and numeric python, there are enough differences to
make manual translation infeasible in real life. SMOP generates
human-readable python, which also appears to be faster than octave.
Just how fast? Timing results for "Moving furniture" are shown
in Table 1. It seems that for this program, translation to python
resulted in about two times speedup, and additional two times speedup
was achieved by compiling SMOP run-time library runtime.py
to C, using cython. This pseudo-benchmark measures scalar
performance, and my interpretation is that scalar computations are
of less interest to the octave team.
======================================== ================== octave-3.8.1 190 ms
smop+python-2.7 80 ms
smop+python-2.7+cython-0.20.1 40 ms
Table 1. SMOP performance
======================================== ==================
News
.. October 23, 2014
Downloaded mybench -- a collection of 20 or so
micro-benchmarks originally meant to compare matlab and
octave performance. After succesfully running the first nine,
the geometric mean of the speedup is 0.36, which is cool.
.. == ======== ====== =========== =======
// name octave smop speedup
== ======== ====== =========== =======
1 rand 2.58 0.36 0.14
2 randn 2.26 1.04 0.46
3 primes 0.35 0.17 0.49
4 fft2 2.75 1.13 0.41
5 square 4.24 0
6 inv 4.38 2.26 0.53
7 eig 17.95 9.09 0.51
8 qr 3.06 1.83 0.60
9 shur 5.98 2.31 0.39
10 roots 8.31 2.02 0.24
== ======== ====== =========== =======
October 15, 2014
Version 0.26.3 is available for beta testing.
Next version 0.27 is planned to compile octave
scripts library, which contains over 120 KLOC in
almost 1,000 matlab files. There are 13 compilation
errors with smop 0.26.3 .
Installation
-
Network installation is the best method if you just want it to run the example::
$ easy_install smop --user
-
Install from the sources if you are behind a firewall::
$ tar zxvf smop.tar.gz $ cd smop $ python setup.py install --user
-
Fork github repository if you need the latest fixes.
-
Finally, it is possible to use smop without doing the installation, but only if you already installed the dependences -- numpy and networkx::
$ tar zxvf smop.tar.gz $ cd smop/smop $ python main.py solver.m $ python solver.py
Working example
We will translate solver.m to present a sample of smop features. The
program was borrowed from the matlab programming competition in 2004 (Moving
Furniture).To the left is solver.m. To the right is a.py --- its
translation to python. Though only 30 lines long, this
example shows many of the complexities of converting matlab code
to python.
.. code:: matlab
01 function mv = solver(ai,af,w) 01 def solver_(ai,af,w,nargout=1): 02 nBlocks = max(ai(:)); 02 nBlocks=max_(ai[:]) 03 [m,n] = size(ai); 03 m,n=size_(ai,nargout=2)
==== ========================================================================= 02 Matlab uses round brackets both for array indexing and for function calls. To figure out which is which, SMOP computes local use-def information, and then applies the following rule: undefined names are functions, while defined are arrays.
03 Matlab function size returns variable number of
return values, which corresponds to returning a tuple
in python. Since python functions are unaware of the
expected number of return values, their number must be
explicitly passed in nargout.
==== =========================================================================
.. code:: matlab
04 I = [0 1 0 -1]; 04 I=matlabarray([0,1,0,- 1]) 05 J = [1 0 -1 0]; 05 J=matlabarray([1,0,- 1,0]) 06 a = ai; 06 a=copy_(ai) 07 mv = []; 07 mv=matlabarray([])
==== =========================================================================
04 Matlab array indexing starts with one; python indexing
starts with zero. New class matlabarray derives from
ndarray, but exposes matlab array behaviour. For
example, matlabarray instances always have at least
two dimensions -- the shape of I and J is [1 4].
06 Matlab array assignment implies copying; python assignment implies data sharing. We use explicit copy here.
07 Empty matlabarray object is created, and then
extended at line 28. Extending arrays by
out-of-bounds assignment is deprecated in matlab, but
is widely used never the less. Python ndarray
can't be resized except in some special cases.
Instances of matlabarray can be resized except
where it is too expensive.
==== =========================================================================
.. code:: matlab
08 while ~isequal(af,a) 08 while not isequal_(af,a): 09 bid = ceil(randnBlocks); 09 bid=ceil_(rand_() * nBlocks) 10 [i,j] = find(a==bid); 10 i,j=find_(a == bid,nargout=2) 11 r = ceil(rand4); 11 r=ceil_(rand_() * 4) 12 ni = i + I(r); 12 ni=i + I[r] 13 nj = j + J(r); 13 nj=j + J[r]
==== =========================================================================
09 Matlab functions of zero arguments, such as
rand, can be used without parentheses. In python,
parentheses are required. To detect such cases, used
but undefined variables are assumed to be functions.
10 The expected number of return values from the matlab
function find is explicitly passed in nargout.
12 Variables I and J contain instances of the new class
matlabarray, which among other features uses one
based array indexing.
==== =========================================================================
.. code:: matlab
14 if (ni<1) || (ni>m) || 14 if (ni < 1) or (ni > m) or (nj<1) || (nj>n) (nj < 1) or (nj > n): 15 continue 15 continue 16 end 16 17 if a(ni,nj)>0 17 if a[ni,nj] > 0: 18 continue 18 continue 19 end 19 20 [ti,tj] = find(af==bid); 20 ti,tj=find_(af == bid,nargout=2) 21 d = (ti-i)^2 + (tj-j)^2; 21 d=(ti - i) ** 2 + (tj - j) ** 2 22 dn = (ti-ni)^2 + (tj-nj)^2; 22 dn=(ti - ni) ** 2 + (tj - nj) ** 2 23 if (d<dn) && (rand>0.05) 23 if (d < dn) and (rand_() > 0.05): 24 continue 24 continue 25 end 25 26 a(ni,nj) = bid; 26 a[ni,nj]=bid 27 a(i,j) = 0; 27 a[i,j]=0 28 mv(end+1,[1 2]) = [bid r]; 28 mv[mv.shape[0] + 1,[1,2]]=[bid,r] 29 end 29 30 30 return mv
Implementation status
.. Table 3. Not compiled
.. =========================== ===================================== stft.m missing semicolon datenum.m missing semicolon orderfields.m legend.m pack.m premature EOF unpack.m premature EOF unimplemented.m premature EOF assert.m optimset.m =========================== =====================================
Random remarks
With less than five thousands lines of python code
SMOP does not pretend to compete with such polished
products as matlab or octave. Yet, it is not a toy.
There is an attempt to follow the original matlab
semantics as close as possible. Matlab language
definition (never published afaik) is full of dark
corners, and SMOP tries to follow matlab as
precisely as possible.
There is a price, too.
The generated sources are
matlabic, rather than pythonic, which means that
library maintainers must be fluent in both languages,
and the old development environment must be kept around.
Should the generated program be pythonic or matlabic?
For example should array indexing start with zero
(pythonic) or with one (matlabic)?
I beleive now that some matlabic accent is unavoidable
in the g
Related Skills
node-connect
337.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.3kCommit, push, and open a PR
