Invocando funções Matlab a partir do Python

 


Se você possui dezenas de funções em Matlab acumuladas ao longo dos anos e deseja aproveitá-las no Python sem precisar reescrever tudo, e ainda com a vantagem tomar proveito da performance superior do Matlab sem abrir mão da flexibilidade do Python, seus problemas acabaram.

Existe uma biblioteca que permite exatamente isso, inclusive com passagem de parâmetros Python  Matlab. A instalação é feita seguindo as orientações contidas em:

 https://www.mathworks.com/help/matlab/matlab_external/install-the-matlab-engine-for-python.html

com a ressalva que se você usa Python em Windows com ambientes virtuais ("virtual envs"), como é o caso do Anaconda e do Django, esse procedimento só funcionará se for executado dentro de um "virtual env", caso contrário você receberá um erro de "acesso negado" (mesmo executando como Administrador e possuindo permissões nas pastas de destino).

Por que invocar funções do Matlab a partir do Python? Bem, isso é útil principalmente para quem tem um vasto portfolio de funções já escritas e testadas em Matlab com as quais está acostumado a lidar. Claro que é preciso ter o Matlab instalado na mesma VM onde se tem o Python instalado; contudo, se essa VM for multiusuária, uma única instalação do Matlab servirá simultaneamente a vários usuários do Python, o que é muito útil em ambientes de desenvolvimento e teste.

Na passagem de parâmetros do Python para o Matlab é preciso ter alguns cuidados, que serão mostrados nos exemplos abaixo.

Suponha que você tem as funções TestaMatlab.m, MatMul.m e DoNothing.m instaladas na pasta C:\Pasta01:

function [t, r, d] = TestMatlab(p)
    t = class(p);
    r = p;
    d = ndims(p);
end

function [p] = MatMul(A, B)
    try
        p = A*B;
    catch
        p = NaN;
    end
end

function [Y] = DoNothing(X)
    Y = X;
end

Suponha ainda que você tem a função Sphere.m instalada na pasta C:\Pasta02:

function z = Sphere(p)
% p deve ser bidimensional
    x=p(1);
    y=p(2);
    z = 3*(1-x).^2.*exp(-(x.^2) - (y+1).^2) ... 
   - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2-y.^2) ... 
   - 1/3*exp(-(x+1).^2 - y.^2) ;
end

O seguinte script Python consumirá as funções acima:

1    import matlab.engine
2    import numpy as np
3    #
4    def main():
5         ml = matlab.engine.start_matlab()
6         ml.cd('C:\\Pasta01')
7         print(ml.plus(2, 3))
8         print(ml.sqrt(float(16)))
9         typeParam = ml.TestMatlab('Matlab')
10        print(typeParam)
11        t, r, d = ml.TestMatlab('Python', nargout=3)
12        print(t)
13        print(r)
14        print(d)
15        A = matlab.int8([3, 6])
16        t, r = ml.TestMatlab(A, nargout=2)
17        print(t)
18        print(r)
19        r = np.asarray(r)
20        print(r)
21        A = matlab.double([1, 2])
22        B = matlab.double([[1, 2], [3, 4]])
23        C = ml.MatMul(A, B)
24        print(C)
25        D = np.asarray(C)
26        print(D)
27        ml.cd("C:\\Pasta02")
28        print(ml.pwd())
29        E = ml.Sphere(matlab.double([1, 1]))
30        print(E)
31        B = np.asarray([[1, 2], [3, 4]])
32        print(B)
33        try:
34            ml.cd('C:\\Pasta01')
35            ml.DoNothing(B) # isso resultará em um erro
36        except:
37            print('erro')
38        print(ml.DoNothing(B.tolist())) # isso está OK
39        A = np.asarray([[1, 2]])
40        print(A)
41        try:
42            ml.cd("C:\\Pasta02")
43            ml.Sphere(A.tolist()) # isso resultará em um erro
44        except:
45            print('erro')
46        print(ml.Sphere(matlab.double(A.tolist()))) # isso está OK
47    #
48    if __name__ == '__main__':
49        main()


A linha 1 necessita que a biblioteca matlab.engine tenha sido previamente instalada no virtual env onde o script irá rodar. 

As linhas 7, 8, 27 e 28 são exemplos de funções nativas do Matlab sendo invocadas no Python. 

As linha 10 e 11 exemplificam que você precisa especificar quantos parâmetros espera receber de volta do Matlab, através do parâmetro nargout=N.

As linhas 38 e 46 mostram que você pode passar listas ou números para o Matlab, mas arrays do Numpy não são aceitos: antes você precisa convertê-los paras listas. Isso é uma desvantagem, pois essa conversão é computacionalmente custosa, mas se você não usar conversões dentro de loops (e via de regra não precisa e nem deve) então não será penalizado em desempenho.

Vale ressaltar que o inverso também é possível, ou seja, invocar funções Python a partir do Matlab. Muito embora o Matlab tenha mais funcionalidades e seja mais performático que o Python, isso pode ser útil em algumas situações.

-X-

Comentários

Postagens mais visitadas deste blog

As Leis de Newton adaptadas às Ciências Sociais e Políticas

Sobre o Óbvio

Verdades, Estatísticas e Probabilidades