Motopy
is a tool used to translate Matlab/Octave code TO PYthon.
Motopy
is a powerful tool used to translate Matlab
/Octave
code to PYthon
. In the process of translation, the python statement generated by mopy
will be executed to ensure the translated correctness of subsequent code. For example, the following Matlab
/Octave
code:
a = ones(1, 3);
b = a';
c = a * b;
will be translated to python
code:
import numpy as np
a = np.ones((1, 3))
b = a.T
c = a @ b
The type of the variables a
and b
are array. So the third statement c = a * b
will be translate to: c = a @ b
.
Please use pip
install motopy
:
pip install motopy
Motopy
is very easy to use. First please prepare your Matlab
/Octave
files, put the script file and the function files with extetion ".m" in a folder, and ensure that your Matlab
/Octave
script can be run without exception. And meet Code Preprocessing.Here's a simple example:
-
Create a folder named "demo".
-
In the "demo" folder, create two ".m" files whose names are "fun.m" and "func_test.m". Input the folowing text:
% file: func.m function s = func(a, b) s = sqrt(a.^2 + b.^2); end
% file: func_test.m a = 3; b = 4; s = func(a, b); disp(s)
-
In the "demo" folder, create a
python
script file. Importmotopy
and usemotopy.make()
translate your mfile:import motopy motopy.make(entry_basename='func_test')
The
entryfile
parameter specifies the mfile script to be translated(***!!Note that there is no extension!! ***).You can also execute the above code directly from the python command line. Ensure that the current directory is the "demo" folder.
The python
script file may not be placed in the same folder as the mfile, and the input mfile and the output python
file may be in a different folder. You can use the input_path
parameter to specify the location of the input mfile and the output_path
parameter to specify the output path of the generated python
file.
import motopy
motopy.make(
entry_basename='<the script filename without extension(*.m)>',
input_path='<the input path of *.m files>',
output_path='<the output path of *.py files>'
)
If you have already translated a function, you can specify an replaced function to that function using the replaced_functions
argument in the motopy.make()
function.
import motopy
motopy.make(
entry_basename='func_test', # no extension
input_path='The path that input ".m" files loaded',
output_path='The path that output ".py" files stored',
replaced_functions={
'func': ('func', 'func') #
}
)
The replaced_functions
parameter is a dictionary, the key is the function name that appears in the mfile, and the value is a tuple (module_name
, function_name
). In the example above, the func
function file will not be translated again.
When do you use replaced_functions
:
-
The
.py
file generated bymotopy
has been modified manually, and do not wantmotopy
to regenerate it. -
The
.m
function thatmotpy
does not support translated yet. You can implement it by yourself.
The code line started with "%%>
" in mfile is a python statment. And will be inserted to generated python
file. And the next statment will be skiped. For example, the mfile:
%%> print('this is a code annotation.')
disp('this statment will be skiped.')
will be translated to:
print('this is a code annotation.')
By default, motopy
generate a log file named "motopy.log" under the output_path
folder. You can use the 'logging_file' parameter to specify the output location and name of the log file. Using logging_level
set log level: WARN|INFO|DEBUG
import motopy
motopy.make(.., logging_level=motopy.DEBUG, ..)
By default, the generated .py
file uses 4 Spaces for indentation. You can use indent
parameter specifies the number of Spaces required for indentation.
The translation will failed if your Matlab
/Octave
code don't satisfy the folowing requirements:
-
Do not use blank spaces to separate elements in arrays and cells. The following code will make failed:
a = [1 2 3; 4 5 6]; c = {1 2 'abc'};
-
The first function name in a function file must be same as the filename.
-
Arrays and cells should be defined before used and allocated enough space. The following code will make failed:
for k=1:5 A(k) = 2*k; % The variable A is not defined before used. end
A = []; % The variable A has not enough space. for k=1:5 A(k) = 2*k; % the size of variable A will grow in iteration. end
-
Do not use "
[]
" to define empty array. The folowing mcode will translate failed:A = []; for k=1:5 B= rand(2,2); A = [A;B]; end disp(A)
The expression
[A;B]
translate failed. because the empty array A with size of0x0
cannot concatenate with array B with size of2x2
.An easy way to resolve this problem is to define the array
A
as an empty array with size of0x2
:A = zeros(0,2); for k=1:5 B= rand(2,2); A = [A;B]; end disp(A)
Matlab/Octave | Python | Note |
---|---|---|
a = [1,2,3,4] |
a = np.array([1, 2, 3, 4]) |
The array in matlab will be translated to np.array |
a = [1,2;3,4] |
a = np.array([[1, 2], [3, 4]]) |
|
a = [1;2;3;4] |
a = np.array([[1], [2], [3], [4]]) |
|
C = {1,2,3;'4',[5,6],{7,8,9}} |
C = [[1, 2, 3], ['4', np.array([5, 6]), [7, 8, 9]]] |
The cell in matlab will be translated to list |
r1 = 1:10; |
r1 = arange(1, 11) |
low_bound:high_bound in matlab will be translated to arange(low_bound, high_boud + 1) |
N = 10; r2 = 1:N; |
N = 10 r2 = arange(1, N + 1) |
|
zeros(3) |
np.zeros((3, 3)) |
|
zeros(2,3) |
np.zeros((2, 3)) |
|
ones(3) |
np.ones((3, 3)) |
|
ones((2, 3)) |
np.ones((2, 3)) |
|
C = cell(2,3) |
C = [[None for _c in range(3)] for _r in range(2)] |
Matlab/Octave | Python | Note |
---|---|---|
a(1,1) |
a[0, 0] |
The value of index will decrease 1, if the index is a number. |
a(1,:) |
a[0, :] |
|
a(:,1) |
a[:, 0] |
|
a(1, 1:2) |
a[0, 0:2] |
|
a(1:2, 1) |
a[0:2, 0] |
|
a(1,2:end) |
a[0, 1:] |
|
m = 1; n = 1; a(m, n*2) |
m = 1 n = 1 a[m - 1, n * 2 - 1] |
The index will be replaced with index - 1 , if index is a variable. |
Matlab/Octave | Python | Note |
---|---|---|
abs |
np.abs |
|
acos |
np.arccos |
|
asin |
np.arcsin |
|
atan |
np.arctan |
|
[y,Fs] = audioread(filename) |
Fs, y = wavfile.read(filename) |
|
ceil |
np.ceil |
|
cos |
np.cos |
|
diag |
np.diag |
|
d = dir(name) |
d = [{'name':e.name, 'folder':e.path, 'isdir':e.is_dir()} for e in scandir(name)] |
|
disp |
print |
|
eye |
np.eye |
|
exp |
np.exp |
|
fft |
np.fft |
|
fix |
np.fix |
|
floor |
np.floor |
|
fprintf |
||
ifft |
np.ifft |
|
inv |
linalg.inv |
|
linspace |
np.linspace |
|
S = load('data.mat') |
S = loadmat('data.mat') |
the Variable S is a dict |
A = load('data.txt') |
A = np.loadtxt('data.txt') |
the file "data.txt" is a ASCII data. |
load('data.mat') |
_mat = loadmat('data.mat'); a = _mat['a']; b = _mat['b'] |
assume there are two variable a and b in "data.mat" |
load('data.txt') |
data = np.loadtxt('data.txt') |
the file "data.txt" is a ASCII data. |
log |
np.log |
|
log10 |
np.log10 |
|
log2 |
np.log2 |
|
mod |
np.mod |
|
ndims |
np.ndim |
|
numel |
np.size |
|
pinv |
linalg.pinv |
|
rand |
random.rand |
|
rank |
linalg.matrix_rank |
|
round |
np.round |
|
sin |
np.sin |
|
sort |
np.sort |
|
sprintf('%d%s',a, b) |
f'{a}{b}' |
|
sqrt |
np.sqrt |
|
s = strcat(s1,...,sN) |
s = ''.join([s1,...,sN]) |
|
unique |
np.unique |
See changelog.md for more information.