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 @ bThe 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 motopyMotopy 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
pythonscript file. Importmotopyand usemotopy.make()translate your mfile:import motopy motopy.make(entry_basename='func_test')
The
entryfileparameter 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
.pyfile generated bymotopyhas been modified manually, and do not wantmotopyto regenerate it. -
The
.mfunction thatmotpydoes 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. endA = []; % 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 of0x0cannot concatenate with array B with size of2x2.An easy way to resolve this problem is to define the array
Aas 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 = 10r2 = 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 = 1n = 1a[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.