Integre código do MATLAB no InfoSphere Streams

Compile funções do MATLAB em bibliotecas C++ e importe no SPL para execução em aplicativos do Streams

MATLAB é uma linguagem e plataforma de computação científica que, devido ao seu forte suporte para manipulação de matriz e sua grande coleção de bibliotecas de modelagem matemática, tornou-se uma escolha de implementação popular para diversos ativos analíticos. Este artigo descreve como as funções do MATLAB podem ser integradas ao SPL para executar código do MATLAB dentro de aplicativos do IBM ® InfoSphere® Streams. A integração não requer quaisquer mudanças ao código do MATLAB. Ela depende do suporte do MATLAB para compilar o código do MATLAB em bibliotecas compartilhadas C++, e do suporte do SPL para fazer a interface com funções nativas.

Bugra Gedik, Dr., Research Staff Member, IBM

Photograph of author Dr. GedikDr. Buğra Gedik é membro do IBM Thomas J. Watson Research Center. Seus interesses de pesquisa atuais estão relacionados aos sistemas de processamento de fluxos distribuídos em grande escala. Mais especificamente, ele trabalha com design de tempo de execução, compilador e design, além de problemas de criação de perfis, otimização e depuração. Ele tem grande envolvimento no desenvolvimento do produto IBM InfoSphere Streams.



05/Jul/2011

Visão geral

Este artigo descreve como executar funções do MATLAB dentro de aplicativos do InfoSphere Streams. O MATLAB é uma linguagem e plataforma de computação científica. Devido ao seu forte suporte para manipulação de matriz e sua grande coleção de bibliotecas de modelagem matemática, ele tornou-se uma escolha de implementação popular para diversos ativos analíticos. A reimplementação desses ativos analíticos em outras linguagens é frequentemente trabalhosa devido à necessidade de encontrar bibliotecas externas que forneçam a funcionalidade já incorporada no MATLAB. Isso cria uma forte motivação para integrar funções escritas no MATLAB em aplicativos do InfoSphere Streams sem reescrever a lógica de função em C++ ou Java™, que são as linguagens de primeira classe suportadas pelo Streams.

O MATLAB oferece suporte à compilação de funções escritas na linguagem de programação do MATLAB (em arquivos .m) em bibliotecas compartilhadas C++. Ele também fornece APIs para escrever código C++ que interaja com a biblioteca gerada, assim como classes de utilitários que fornecem tipos de dados de matriz. Além disso, o MATLAB também fornece uma biblioteca de tempo de execução para fazer links, para aplicativos que usam as rotinas do MATLAB compiladas em C++. A abordagem geral da integração de funções do MATLAB no Streams é a seguinte:

  1. Desenvolva sua(s) função(ões) do MATLAB.
  2. Use o compilador do MATLAB para criar uma biblioteca compartilhada C++.
  3. Crie uma função nativa em SPL que encapsule a biblioteca compartilhada C++.
  4. Escreva um aplicativo do SPL que use as funções ativas.

Essas etapas são ilustradas pela amostra a seguir.

Desenvolva sua função do MATLAB

Você escreverá uma função simples do MATLAB que executa a inversão de matriz.

Crie um diretório chamado Matlab_inv e coloque nele um arquivo chamado ml_inv.m , com o seguinte conteúdo:

  function out = ml_inv(in)
  % ML_INV Matrix inverse
  % Invert a given matrix
  out = inv(in);

Seu objetivo é ser capaz de usar essa função inversa de matriz no código SPL. Segue uma amostra de função SPL que utiliza a função inversa de matriz ml::inv que encapsula a função ml_inv do MATLAB. No restante deste artigo, você observará as etapas necessárias para criar o ml::inv .

  void foo() 
  {   // Sample SPL code that uses the matrix inverse
      list<list<float64>> inM = [[1.0,3.0],[2.0,4.0]];
      mutable list<list<float64>> outM = [];
      ml::inv(outM, inM); // ml::inv is the wrapper for ml_inv
  }

Use o compilador do MATLAB para criar uma biblioteca compartilhada C++.

Você usará o compilador do MATLAB para criar uma biblioteca compartilhada C++ que conterá a função de inversão de matriz.

  1. Na linha de comando do MATLAB, digite deploytool.
  2. Siga a interface gráfica para criar um projeto de implementação chamado libMatlab_inv no diretório Matlab_inv .
  3. Clique no botão Add File para incluir o arquivo ml_inv.m no projeto.
  4. Clique no botão Build para criar a biblioteca compartilhada.

Os seguintes arquivos de resultado serão gerados no diretório Matlab_inv/libMatlab_inv/distrib .

  • libMatlab_inv.h: este é o arquivo de interface que declara as funções C++ geradas a partir do código do MATLAB.
  • libMatlab_inv.so: esta é a biblioteca compartilhada que contém as implementações de função C++ geradas a partir do código do MATLAB.
  • libMatlab_inv.exports: este é um arquivo de texto que relaciona o nome das funções exportadas pela biblioteca. Este arquivo não é obrigatório para a operação da biblioteca.
  • libMatlab_inv.ctf e libMatlab_inv_mcr: o primeiro é um archive, a partir do qual o segundo diretório é criado pelo compilador do MATLAB. Estes contêm bibliotecas de suporte adicionais. Elas devem estar localizadas no mesmo local da biblioteca compartilhada .so .

Experimente a biblioteca compartilhada em um aplicativo C++ independente

Antes de usar a biblioteca compartilhada em um aplicativo do Streams, você a experimentará em um aplicativo C++ independente.

Crie um diretório chamado sample_c++ no mesmo nível do Matlab_inv. Dentro desse diretório, crie um arquivo chamado sample.cpp e preencha-o da seguinte forma:

  #include "libMatlab_inv.h"
  int main()
  {
      libMatlab_invInitialize();
      double data[] = {1.0, 2.0, 3.0, 4.0};
      mwArray in(2,2,mxDOUBLE_CLASS);
      mwArray out(2,2,mxDOUBLE_CLASS);
      in.SetData(data, 4);
      ml_inv(1, out, in);
      std::cerr << "[" << out(1,1) << ", " << out(1,2) << "; "
                       << out(2,1) << ", " << out(2,2) << "]\n";
      libMatlab_invTerminate();
      return 0;
  }

No código acima, a função libMatlab_invInitialize é chamada para inicializar o tempo de execução do MATLAB. Essa é uma das funções geradas para você pelo compilador do MATLAB. Você então cria estas duas matrizes: in e out. O mwArray é uma classe C++ fornecida pelas APIs C++ do MATLAB para trabalhar com matrizes. É possível usar a função ml_inv para tomar o inverso da matriz in e atribuí-lo à matriz out . Essa é a função principal gerada para você pelo compilador do MATLAB, com base na função do MATLAB com o mesmo nome a partir do arquivo ml_inv.m . Finalmente, a função libMatlab_invTerminate é chamada para finalizar o tempo de execução do MATLAB. Novamente, essa é uma função gerada para você pelo compilador MATLAB.

Para compilar esse programa, crie um Makefile da seguinte forma:

.PHONY: all clean
MATLAB_LIBRARY_LOCATION := /nfs/hny/apps01/matlab/bin/glnxa64/
MATLAB_INCLUDE_LOCATION := /nfs/hny/apps01/matlab/extern/include/
all: 
	g++ -o sample sample.cpp                           \
            -I ../Matlab_inv/libMatlab_inv/distrib         \
            -I $(MATLAB_INCLUDE_LOCATION)                  \
            -L ../Matlab_inv/libMatlab_inv/distrib         \
	    -Wl,-rpath,../Matlab_inv/libMatlab_inv/distrib \
            -L $(MATLAB_LIBRARY_LOCATION)                  \
	    -Wl,-rpath,/nfs/hny/apps01/matlab/bin/glnxa64/ \
            -lMatlab_inv -lmwmclmcrrt 

clean:
	rm sample

Seguem abaixo alguns pontos que você deve observar:

  • O caminho de inclusão -I ../Matlab_inv/libMatlab_inv/distrib é usado para especificar o local do arquivo de interface (libMatlab_inv.h) gerado pelo compilador do MATLAB.
  • O caminho de inclusão -I $(MATLAB_INCLUDE_LOCATION) é usado para especificar o local dos arquivos de interface para as APIs C++ do MATLAB. Esse local será específico ao seu ambiente e dependerá do local da instalação do MATLAB. A variável $(MATLAB_INCLUDE_LOCATION) deve ser definida apropriadamente.
  • O caminho da biblioteca -L ../Matlab_inv/libMatlab_inv/distrib é usado para especificar o local da biblioteca libMatlab_inv.so) gerada pelo compilador do MATLAB. Um RPATH é especificado usando o mesmo caminho para o local do tempo de execução da biblioteca.
  • O caminho da biblioteca -L $(MATLAB_LIBRARY_LOCATION) é usado para especificar o local das bibliotecas de tempo de execução do MATLAB. Esse local será específico ao seu ambiente e depende do local da instalação do MATLAB e da arquitetura do seu sistema. A variável $(MATLAB_LIBRARY_LOCATION) deve ser definida apropriadamente.
  • A biblioteca -lMatlab_inv deve ser usada para especificar o nome da biblioteca gerada pelo compilador do MATLAB (libMatlab_inv.so).
  • A biblioteca -lmwmclmcrrt é usada para especificar o nome da biblioteca de tempo de execução do MATLAB (libmwmclmcrrt.so).

Simplesmente digite make para desenvolver a biblioteca e ./sample para executá-la. A seguinte saída deve ser produzida: [-2, 1.5000; 1, -0.5000].

Crie uma função nativa no SPL que encapsule a biblioteca compartilhada C++

Você criará funções nativas no SPL que fazem uso das funções geradas pelo compilador do MATLAB. Isso pode ser feito de duas maneiras. É possível criar um kit de ferramentas que encapsula todas as funções nativas, ou inclui funções nativas diretamente em um aplicativo. A primeira opção é mais apropriada se houver aplicativos que usarão as funções. Para concisão, use esta segunda abordagem.

  1. Crie um diretório chamado sample_spl no mesmo nível que Matlab_inv e sample_c++. Esse será seu diretório de aplicativos.
  2. Crie um subdiretório chamado ml. Esse será seu diretório de espaço de nome.
  3. Em ml, crie um subdiretório chamado native.function, que manterá o modelo de função.
  4. Nesse diretório, inclua o arquivo de modelo de função chamado function.xml, que contém o seguinte conteúdo.
<functionModel
   xmlns="http://www.ibm.com/xmlns/prod/streams/spl/function"
   xmlns:cmn="http://www.ibm.com/xmlns/prod/streams/spl/common"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.ibm.com/xmlns/prod/streams/spl/function 
                       functionModel.xsd">
  <functionSet>
    <headerFileName>spl_ml_inv.h</headerFileName>
    <functions>
      <function>
        <description>Take inverse of a matrix</description>
        <prototype><![CDATA[ public void inv(mutable list<list<float64>> r,
                             list<list<float64>> s) ]]></prototype>
      </function>
      <function>
        <description>Initialize Matlab runtime</description>
        <prototype><![CDATA[ public void initialize() ]]></prototype>
      </function>
      <function>
        <description>Finalize Matlab runtime</description>
        <prototype><![CDATA[ public void terminate() ]]></prototype>
      </function>
    </functions>
    <dependencies>
      <library>
        <cmn:description>Matrix inverse</cmn:description>
        <cmn:managedLibrary>
          <cmn:lib>Matlab_inv</cmn:lib>
          <cmn:lib>mwmclmcrrt</cmn:lib>
          <cmn:libPath>../../impl/lib</cmn:libPath>
          <cmn:libPath>/nfs/hny/apps01/matlab/bin/glnxa64/</cmn:libPath>
          <cmn:includePath>../../impl/include</cmn:includePath>
          <cmn:includePath>/nfs/hny/apps01/matlab/extern/include/</cmn:includePath>
        </cmn:managedLibrary>
      </library>
    </dependencies>
  </functionSet>
</functionModel>

No arquivo de modelo de função acima, há algumas coisas a serem observadas:

  • O arquivo spl_ml_inv.h é o arquivo de cabeçalho que contém as funções C++ que encapsularão as funções geradas pelo MATLAB.
  • As três funções nativas do SPL inv, initialize e terminate correspondem às três funções ml_inv, libMatlab_invInitialize e libMatlab_invTerminate geradas pelo compilador do MATLAB. Observe que a função inv usa listas aninhadas do SPL para representar matrizes, já que não há tipos de matriz no SPL. Como você verá, a função inv também executará a conversão entre tipos C++ do SPL e tipos C++ do MATLAB.
  • As bibliotecas Matlab_inv e mwmclmcrrt são especificadas como dependências, incluindo seus caminhos de biblioteca e caminhos de inclusão. Observe que os caminhos de inclusão e de biblioteca para as bibliotecas Matlab_inv são especificados relativos ao arquivo de modelo.

Agora, copie os arquivos relevantes para o subdiretório impl ,no diretório do aplicativo sample_spl , para tornar o aplicativo independente.

  1. Crie um diretório impl no diretório de aplicativo sample_spl.
  2. Crie dois subdiretórios em impl: include e lib. Copie o arquivo libMatlab_inv.h do diretório Matlab_inv/libMatlab_inv/distrib para o diretório include .
  3. Agora copie os arquivos libMatlab_inv.so e libMatlab_inv.ctf , assim como o diretório libMatlab_inv_mcr , para o diretório lib .
  4. Finalmente, crie o arquivo de cabeçalho de wrapper spl_ml_inv.h no diretório include , com o seguinte conteúdo.
  #include "libMatlab_inv.h"
  namespace ml {
      void initialize() {
          libMatlab_invInitialize();
      }
      void terminate() {
          libMatlab_invTerminate();
      }
      void inv(SPL::list<SPL::list<SPL::float64> > & lhs,
               SPL::list<SPL::list<SPL::float64> > const & rhs)
      {
          size_t nr = rhs.size(), nc = rhs[0].size();
          mwArray in(nr, nc, mxDOUBLE_CLASS);
          mwArray out(nr, nc, mxDOUBLE_CLASS);
          for(size_t r=0; r<nr; ++r)
              for(size_t c=0; c<nc; ++c)
                  in(r+1,c+1) = rhs[r][c];
          ml_inv(1, out, in);
          lhs.resize(nr);
          for(size_t r=0; r<nr; ++r) {
              lhs[r].resize(nc);
              for(size_t c=0; c<nc; ++c)
                  lhs[r][c] = out(r+1,c+1);  
          }      
      }
  }

No código anterior, a função inv executa transformações entre os tipos de list do SPL e os tipos de mwArray do MATLAB para encapsular a função ml_inv gerada pelo compilador do MATLAB. Observe que todas as funções de wrapper são colocadas no espaço de nome ml, já que seu diretório native.function está no diretório de espaço de nome ml.

Escreva um aplicativo do SPL que use as funções nativas.

Escreva um aplicativo do SPL que usa as funções nativas para encapsular as funções geradas pelo compilador do MATLAB.

Crie um arquivo chamado Main.spl no diretório sample_spl junto com o seguinte conteúdo:

  composite Main {
      graph
          stream<int8 dummy> Beat = Beacon() { 
              param iterations : 1u; 
          }
          () as Sink = Custom(Beat) {
              logic
                  onTuple Beat: {
                      ml::initialize();
                      list<list<float64>> inM = [[1.0,3.0],[2.0,4.0]];
                      mutable list<list<float64>> outM = [];
                      ml::inv(outM, inM);
                      println(outM);
                      ml::terminate();
                  }
          }
  }

Este é um aplicativo de amostra do SPL que inicializa o tempo de execução do MATLAB, executa uma inversão de matriz por meio da função ml::inv e finaliza o tempo de execução do MATLAB.

  1. Digite sc -m -M Main no diretório sample_spl para criar um Makefile para este aplicativo.
  2. Então, digite make standalone para compilá-lo.
  3. É possível que alguns avisos sejam exibidos. Ignore os avisos supérfluos (versões futuras do Streams podem incluir suporte para suprimir esses avisos) e digite ./output/bin/standalone para executar o aplicativo. Deve-se encontrar o seguinte resultado: [[-2,1.5],[1,-0.5]].

Conclusão

Neste artigo, você viu como integrar funções do MATLAB em aplicativos do Streams sem reescrever a lógica das funções em uma linguagem diferente. A abordagem utiliza o compilador do MATLAB para converter o código do MATLAB em bibliotecas compartilhadas C++, escrevendo uma função C++ nativa que encapsula essa biblioteca compartilhada e importando a função de wrapper para o SPL usando um modelo de função. O código de origem para o exemplo dado em nossa discussão é fornecido neste artigo.


Download

DescriçãoNomeTamanho
Sample code for this articleMatlabStreamsIntegration.zip322KB

Recursos

Aprender

Obter produtos e tecnologias

  • Crie seu próximo projeto de desenvolvimento com a versão de teste do software IBM, disponível para download diretamente no developerWorks, ou dedique algumas horas à SOA Sandbox aprendendo como implementar Arquitetura Orientada a Serviços de forma eficiente.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=697383
ArticleTitle=Integre código do MATLAB no InfoSphere Streams
publish-date=07052011