我的开源项目之Matlab/Octave转Python工具(motopy)
目录
- Motopy
- 介绍
- 安装
- 快速开始
- 指定输入输出文件夹
- 指定替代函数
- 日志信息
- 缩进
- motopy的使用要求
- 已实现的转换
- 矩阵, 数组和元胞的创建
- 矩阵, 数组和元胞的切片
- 函数
- 说明
Motopy
介绍
motopy
是一款功能强大(😊自吹吧)的 Matlab
/Octave
转 PYthon
工具. 在转换的过程中, 自动执行转换后的python
语句, 保证转换过程的正确性. 例如下述Matlab
/Octave
代码:
a = ones(1, 3);
b = a';
c = a * b;
将转换为:
import numpy as np
a = np.ones((1, 3))
b = a.T
c = a @ b
变量 a
和 b
的值类型均为数组类型. 所以在转换第三条语句 c = a * b
时, 将会转换为: c = a @ b
.
点击 github链接, 访问我的代码仓库.
安装
使用 pip
安装 motopy
.
pip install motopy
快速开始
motopy
使用起来及其简单, 首先请准备好你的Matlab/Octave
文件, 将脚本文件(*.m)和其调用的函数文件放置在同一个文件夹, 保证你的Matlab/Octave
脚本能够正常运行, 并且满足motopy
的使用要求. 下面我将给出一个简单的例子:
-
创建名为"demo"的文件夹.
-
在"demo"文件夹下, 创建两个.m文件, 文件名分别为"func.m" 和 “func_test.m”, 文件内容如下:
% 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)
-
在"demo"文件夹中, 创建一个
python
脚本文件, 导入motopy
, 并调用motopy.make()
完成代码的转换.python
脚本内容如下:import motopy motopy.make(entryfile='func_test')
entryfile
参数用于指定要转换的m文件的脚本入口(!!注意, 此处不加扩展名!!).当然, 你也可以直接在
python
命令行中执行上述代码. 请保证当前目录是"demo"文件夹.
指定输入输出文件夹
python
脚本文件可以不放置到m文件所在文件夹中, 输入的m文件和输出的py文件也可以位于不同的文件夹中. 此时可以使用input_path
参数指定输入m文件所在位置, 使用output_path
参数指定生成的python
文件的输出路径.
import motopy
motopy.make(
entry_basename='func_test', # no extension
input_path='输入m文件所在路径',
output_path='输出py文件所在路径')
指定替代函数
如果你已经完成了某个函数的转换, 可以通过motopy.make()
函数中的 replaced_functions
参数指定此函数的替代函数.
import motopy
motopy.make(
entry_basename='func_test', # no extension
input_path='输入m文件所在路径',
output_path='输出py文件所在路径',
replaced_functions={
'func': ('func', 'func') #
}
)
replaced_functions
参数为一个字典, 键为m文件中出现的函数名, 值为二元元组(模块名
, 函数名
). 上述示例中, func
函数文件将不会再次转换.
什么情况下使用replaced_functions
?
motopy
生成的py
文件, 我们对其进行了修改, 并且不希望motopy
重新生成它.- 对于某些m函数, 我们知道
python
中有功能一致, 且参数对应的函数与其等价. 比如: ceil <–> np.ceil, 我们可以在replaced_functions
中添加'ceil': ('numpy', 'ceil')
日志信息
默认在output_path
文件夹下生成名为"motopy.log"日志文件. 可以通过logging_file
参数, 指定日志文件的输出位置和名称. 使用logging_level
设置日志等级: WARN|INFO|DEBUG
import motopy
motopy.make(.., logging_level=motopy.DEBUG, ..)
缩进
默认生成的py文件使用4个空格进行缩进, 可以通过indent
参数指定缩进所需的空格数.
motopy的使用要求
因为motopy
采用边转译边执行的方式进行转换. 所以转换可能失败. 为了提高转换的成功率. 请对你的".m"代码进行适当修改.
-
数组和元胞中的元素请不要使用空格进行分隔. 下述代码是一个错误示例:
a = [1 2 3; 4 5 6]; c = {1 2 'abc'};
-
函数文件的名称和函数名必须相同.
-
数组和元胞应该事先定义, 且分配足够大的空间. 下述代码是一个错误示例:
for k=1:5 A(k) = 2*k; % A 在赋值之前没有定义. end
A = []; % 虽然定义了A, 但是没有给足够大的空间 for k=1:5 A(k) = 2*k; % A的大小在迭代的过程中改变了 end
已实现的转换
矩阵, 数组和元胞的创建
Matlab/Octave | Python | Note |
---|---|---|
a = [1,2,3,4] | a = np.array([1, 2, 3, 4]) | matlab中的数组会被转换为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]]] | matlab 的 cell 会被转换成 python 中的list |
r1 = 1:10; | r1 = arange(1, 11) | 上限自动+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)) |
矩阵, 数组和元胞的切片
Matlab/Octave | Python | Note |
---|---|---|
a(1,1) | a[0, 0] | 如果索引为数值, 使用减1后的值替代 |
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] | 如果索引为变量或表达式, 则对变量或表达式-1 |
函数
Matlab/Octave | Python | Note |
---|---|---|
acos | np.arccos | |
asin | np.arcsin | |
atan | np.arctan | |
ceil | np.ceil | |
cos | np.cos | |
diag | np.diag | |
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 | |
log | np.log | |
log10 | np.log10 | |
log2 | np.log2 | |
ndims | np.ndim | |
numel | np.size | |
pinv | linalg.pinv | |
rank | linalg.matrix_rank | |
round | np.round | |
sin | np.sin | |
sort | np.sort | |
sprintf('%d%s',a, b) | f'{a}{b}' | |
sqrt | np.sqrt | |
unique | np.unique |
说明
Motopy
目前处于开发阶段, 如果你在使用的过程中发现任何关于motopy
的问题, 烦请提交至Issues, 或邮件告知(falwat@163.com), 留言亦可. 我将在后续版本中更新修复. 感谢使用motopy
.